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

如何实现类似Lombok @Getter的替代值获取功能?

解决方案:字段为null时取备选字段值的实现

一、直接手动实现(简单高效)

如果只是个别字段需要这个逻辑,没必要折腾自定义注解,直接在DTO中手动编写方法即可:

@Getter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class SomeDto extends BaseDto {

    private BigDecimal a;

    private BigDecimal b;

    // 自定义方法,当b为null时返回a的值
    public BigDecimal getBOrAlternative() {
        return Objects.nonNull(b) ? b : a;
    }
}

直接调用dto.getBOrAlternative()就能满足需求,无需额外配置。

二、自定义Lombok注解+处理器(复用场景)

如果多个字段需要类似逻辑,可以通过自定义Lombok注解实现自动生成方法,解决你之前未成功的核心问题——针对字段级别处理:

1. 定义字段级注解

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

@Target(ElementType.FIELD) // 指定注解作用于字段
@Retention(RetentionPolicy.SOURCE) // 仅在编译期生效
public @interface GetOrAlternative {
    String alternative(); // 配置备选字段名
}

2. 编写Lombok注解处理器(字段级别处理)

需要使用Lombok的AbstractAnnotationHandler来操作编译期AST(抽象语法树),避免和@Getter等注解冲突:

import lombok.core.AnnotationValues;
import lombok.core.handlers.HandlerUtil;
import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacNode;
import lombok.javac.JavacTreeMaker;
import org.mangosdk.spi.ProviderFor;

import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCBlock;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCReturn;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.util.List;

@ProviderFor(JavacAnnotationHandler.class)
public class HandleGetOrAlternative extends JavacAnnotationHandler<GetOrAlternative> {

    @Override
    public void handle(AnnotationValues<GetOrAlternative> annotation, JCTree.JCAnnotation ast, JavacNode node) {
        if (node.getKind() != ElementKind.FIELD) {
            node.addError("@GetOrAlternative只能用于字段");
            return;
        }
        
        JCVariableDecl field = (JCVariableDecl) node.get();
        String alternativeField = annotation.getInstance().alternative();
        String fieldName = field.name.toString();
        // 生成方法名:get + 首字母大写字段名 + OrAlternative
        String methodName = "get" + capitalize(fieldName) + "OrAlternative";
        
        JavacTreeMaker treeMaker = node.getTreeMaker();
        // 构建方法体:return this.b != null ? this.b : this.a;
        JCExpression fieldAccess = treeMaker.Select(treeMaker.Ident(node.toName("this")), node.toName(fieldName));
        JCExpression altFieldAccess = treeMaker.Select(treeMaker.Ident(node.toName("this")), node.toName(alternativeField));
        JCExpression condition = treeMaker.Binary(com.sun.tools.javac.code.TypeTags.NE, fieldAccess, treeMaker.Literal(null));
        JCExpression ternary = treeMaker.Conditional(condition, fieldAccess, altFieldAccess);
        JCBlock body = treeMaker.Block(0, List.of(treeMaker.Return(ternary)));
        
        // 构建方法声明
        JCMethodDecl method = treeMaker.MethodDef(
            treeMaker.Modifiers(Flags.PUBLIC),
            node.toName(methodName),
            field.vartype,
            List.nil(),
            List.nil(),
            List.nil(),
            body,
            null
        );
        
        // 将方法注入到类中
        HandlerUtil.injectMethod(node.up(), method);
    }
    
    private String capitalize(String str) {
        if (str == null || str.isEmpty()) return str;
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }
}

3. 注册处理器

在项目的src/main/resources/META-INF/services目录下创建文件javax.annotation.processing.Processor,写入处理器全类名:

com.yourpackage.HandleGetOrAlternative

4. 使用注解

回到你的DTO类,即可正常使用注解:

@Getter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class SomeDto extends BaseDto {

    private BigDecimal a;

    @GetOrAlternative(alternative = "a")
    private BigDecimal b;
}

编译后会自动生成getBOrAlternative()方法,调用逻辑和手动实现一致。

为什么之前自定义注解失败?

你之前的问题大概率是没有使用Lombok的AST处理机制,而是用了普通的Java注解处理器直接生成源文件,导致和@Getter等Lombok注解的编译期逻辑冲突,且没有正确针对字段级别注入方法。使用Lombok官方的AbstractAnnotationHandler能完美适配Lombok的编译流程,实现字段级别的方法生成。

内容的提问来源于stack exchange,提问作者김효성

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 13:55:37