lombok的Data注解导致Set去重失效问题

背景

   final Set<AbstractMetadataCard> datas = new HashSet<>(hits.length);
        Arrays.asList(hits).forEach(hit -> {
            final AllFiledMetadata data = JSONObject.parseObject(hit.getSourceAsString(), AllFiledMetadata.class);
            final AbstractMetadataCard card = data.parse(search);
            if (card == null) {
                return;
            }
            datas.add(card);
        });

在拿到一批数据的时候需要进行解析+去重+返回接口数据。以下代码中AbstractMetadataCard类是父类,派生了10个子类,每个解析的逻辑在子类中分别实现,最终子类解析出的返回值都是父类类型,由于去重逻辑相同,所以hashCode和equals方法我写在了父类中。

特殊的点是我的子类中没有一个属性,只有parse的业务逻辑,属性都定义在父类中。下面列举其中一个子类和父类的代码:

父类:

@Data
public abstract class AbstractMetadataCard implements Serializable {
    private static final long serialVersionUID = 1717719806335115651L;
    /**
     * 类型
     */
    private Integer type;
    /**
     * 主信息
     */
    private String masterName;
    /**
     * 附属信息
     */
    private String slaveName;

    public abstract AbstractMetadataCard parse(final AllFiledMetadata metadata, String search);

    @Override
    public boolean equals(final Object data) {
        if (this == data) {
            return true;
        }
        if (!(data instanceof AbstractMetadataCard)) {
            return false;
        }
        final AbstractMetadataCard target = (AbstractMetadataCard) data;
        if (Objects.equals(target.getMasterName(), this.getMasterName())
                && Objects.equals(target.getSlaveName(), this.getSlaveName()) &&
                Objects.equals(target.getType(), this.getType())) {
            return true;
        }
        return false;
    }

    @Override
    public int hashCode() {
        if (masterName != null && slaveName != null && type != null) {
            return masterName.hashCode() + slaveName.hashCode() + type.hashCode();
        }
        return masterName.hashCode() + type.hashCode();
    }

子类:

@Data
public class ApplicationCard extends AbstractMetadataCard {

    private static final long serialVersionUID = 5449872075497237059L;

    @Override
    public ApplicationCard parse(final AllFiledMetadata metadata, final String search) {
        if (!Objects.equals(metadata.getMwtype(), APPLICATION.getValue())) {
            return null;
        }
        final ApplicationCard applicationMetadata = new ApplicationCard();
        applicationMetadata.setSlaveName(metadata.getDevMaster());
        applicationMetadata.setMasterName(metadata.getApplication());
        applicationMetadata.setType(APPLICATION.getValue());
        return applicationMetadata;
    }}

现象

我查询出来的数据有很多条,但是最终接口返回都是1条数据,很明显是被错误去重了,检查了下父类的equals和hashCode方法都没有问题,思考了半天不知道什么原因,debug父类的equals和hashCode方法都没有被调用,甚至还跟了下hashMap的源码,也没解决。

结论

最终我编译了一下子类然后再反编译出来查看了下代码,我发现子类里面怎么多了4个方法,equals、hashCode、toString、canEqual

public class ApplicationCard extends AbstractMetadataCard {
    private static final long serialVersionUID = 5449872075497237059L;

    public ApplicationCard parse(final AllFiledMetadata metadata, final String search) {
        if (!Objects.equals(metadata.getMwtype(), MetadataSourceTypeEnum.APPLICATION.getValue())) {
            return null;
        } else {
            ApplicationCard applicationMetadata = new ApplicationCard();
            applicationMetadata.setSlaveName(metadata.getDevMaster());
            applicationMetadata.setMasterName(metadata.getApplication());
            applicationMetadata.setType(MetadataSourceTypeEnum.APPLICATION.getValue());
            return applicationMetadata;
        }
    }

    public ApplicationCard() {
    }

    public boolean equals(final Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof ApplicationCard)) {
            return false;
        } else {
            ApplicationCard other = (ApplicationCard)o;
            return other.canEqual(this);
        }
    }

    protected boolean canEqual(final Object other) {
        return other instanceof ApplicationCard;
    }

    public int hashCode() {
        int result = true;
        return 1;
    }

    public String toString() {
        return "ApplicationCard()";
    }
}

原来,lombok的@Data注解会帮你自动生成这几个方法,但是大家可以看下我生成的这个hashCode方法和equals和canEqual方法,hashmap在进行key去重的时候,会先比较对象中的hashCode方法,很明显,这里永远返回true,如果hashCode返回的值相等,那就说明hash冲突了,冲突以后会去比较equals方法,如果相等则替换,如果不等,则以链表或者红黑树的形式存在,很明显,这里equals方法判断都是这个子类对象的时候,就是相等的。

那为什么我父类重写的hashCode方法没有被调用呢?因为子类lombok已经帮我写了,优先调用子类本身的方法。

总结

出现此问题的场景有一个比较特殊的场景:我的子类没有任何属性,所以lombok写了一个相当于永远返回true的几个方法。而且其实idea在编译的时候会做提示,因为注解在类上面,所以我没有注意到。

公众号

微信搜索“PPShare”,关注公众号。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可能是因为您没有正确地配置Lombok插件或者没有在类上添加Lombok注解。请确保您已经正确地安装了Lombok插件,并在需要使用Lombok的类上添加了相应的注解,例如@Data、@Getter、@Setter等。如果仍然无法解决问题,请检查您的IDE是否支持Lombok插件。 ### 回答2: Lombok是一个开源的Java库,在很大程度上简化了Java代码的编写工作。其中一项重要的功能是可以通过注解自动生成getter和setter方法。使用Lombok可以减少代码的冗余,提高代码的可读性和可维护性,但是有时候可能会出现Lombok的getter和setter方法失效的情况,原因可能有以下几个方面: 1.未按照Lombok的使用方法 在使用Lombok之前,我们需要在项目中引入相应的Lombok依赖。在编写Java类时,需要使用Lombok注解来生成相应的getter和setter方法。如果注解使用不当或者缺失,就会导致Lombok的get和set方法失效。 2.版本不兼容 Lombok依赖的版本可能会和当前项目的Java版本不一致,如果Lombok版本过低,可能会导致getter和setter方法失效。另外,在IDE中也需要安装相应的Lombok插件,以确保生成的getter和setter方法可以被正确识别。 3.源码编码不规范 有时候,我们可能会忽略Lombok自动生成的getter和setter方法,手动编写相应的方法。如果手动编写的方法与Lombok生成的方法名称、参数类型和返回类型不一致,就会导致Lombok生成的getter和setter方法失效。 以上是Lombok的get和set方法失效的几个常见原因。在使用Lombok时,我们需要注意以上几点,避免出现不必要的问题。同时,在编写Java代码时,不应该完全依赖于Lombok的自动生成功能,合理编写相应的getter和setter方法,以减少不必要的麻烦。 ### 回答3: Lombok 是一个 Java注解库,使用它可以简化代码,并且提高代码的可读性。其中,最常用的注解就是 @Data,它会自动为所有属性生成 getter 和 setter 方法。但是,在实际开发中,我们发现有时候 Lombok 的 getter 和 setter 方法会失效,这个问题可能是由以下几个原因引起的: 1. IDE 不支持 Lombok 这个问题比较常见,如果你使用的 IDE 不支持 Lombok,那么 Lombok 生成的代码就会失效。例如,在 Eclipse 中安装 Lombok 需要手动安装插件,否则就无法使用。 2. Lombok 版本不兼容 如果你的 Lombok 版本过低或过高,也会导致生成的代码失效。建议使用与当前项目兼容的 Lombok 版本。 3. 编译器不支持 Lombok 有时候编译器也可能不支持 Lombok,这时候就需要在项目中加入 Lombok 的相关依赖。 4. 编译器缓存 在编译过程中,编译器会对代码进行缓存,如果你修改了代码但是编译器缓存没有更新,会导致 Lombok 生成的代码失效。在这种情况下,建议清除编译器缓存并重新编译。 5. 编译器配置问题 如果你的编译器配置不正确,也有可能导致 Lombok 生成的代码失效。比如,编译器没有正确设置 Lombok 注解处理器。 总之,在使用 Lombok 时,要注意以上几个问题,如果出现问题,可以尝试通过升级 Lombok 或重新配置编译器等方式解决。如果问题比较棘手,可以在 Lombok 的官方网站上寻求帮助或反馈问题

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值