Lombok @Data导致的hashCode的问题

Lombok @EqualsAndHashCode 配置自定义hashCode方法

目录

背景

Entity
一个User包含多个AbstractUser。在jpa查询中因为用到left join fetch,导致查询结果AbstractUser重复,而又没有办法在第二层利用distinct关键字去重AbstractUser,所以利用SET来过滤。但是利用Lombok的@DATA注解导致错误。

User

@Entity
@Table(name = "user")
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
public class User{
	@Id
    @GeneratedValue
    @Column(name = "uuid")
	private UUID id;
	
	@Column(name = "name", nullable = false)
	private String name;

	@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
	private Set<AbstractUser> abstractUsers;	
}

AbstractUser

@Entity
@Table(name = "abstract_user")
@Slf4j
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
public class AbstractUser implements Serializable{
    /**
	 * 
	 */
    
    /** The unique identifier */
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    @Column(name = "uuid", unique = true, nullable = false)
    @Id
    private String id;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    @JsonIgnore
    private User user;
}

利用下面的JPA语句查询的时候报错了

@Query("select distinct u from User u left join fetch u.abstractUsers as au "
			+ "where (:username is null or lower(u.name)=lower(:username)) "
			+ "and (:abstractUserId is null or au.id=:abstractUserId ")
	List<User> findUsers(@Param("username") String username, @Param("abstractUserId") String abstractUserId);

问题

java.lang.NullPointerException: null
at org.hibernate.engine.internal.StatefulPersistenceContext.getLoadedCollectionOwnerOrNull(StatefulPersistenceContext.java:789) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.event.spi.AbstractCollectionEvent.getLoadedOwnerOrNull(AbstractCollectionEvent.java:58) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.event.spi.InitializeCollectionEvent.(InitializeCollectionEvent.java:22) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:2244) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:580) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:262) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:576) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:147) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:458) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at com.test.AbstractUser.hashCode(AbstractUser.java:43) ~[classes/:na]
at java.util.HashMap.hash(Unknown Source) ~[na:1.8.0_151]
at java.util.HashMap.put(Unknown Source) ~[na:1.8.0_151]
at java.util.HashSet.add(Unknown Source) ~[na:1.8.0_151]
at java.util.AbstractCollection.addAll(Unknown Source) ~[na:1.8.0_151]

原因

@Data相当于@Getter @Setter @RequiredArgsConstructor @ToString ``@EqualsAndHashCode这5个注解的合集。
当使用@Data注解时,则有了@EqualsAndHashCode注解,那么就会在此类中存在equals(Object other) 和 hashCode()方法,且不会使用父类的属性,这就导致了可能的问题。
比如,有多个类有相同的部分属性,把它们定义到父类中,恰好id(数据库主键)也在父类中,那么就会存在部分对象在比较时,它们并不相等,却因为lombok自动生成的equals(Object other) 和 hashCode()方法判定为相等,从而导致出错。
hashSet过滤去重的时候使用hashCode方式生成的hashcode来判别对象是否重复。lombok的@Data注解生成的hashCode()导致出错。

解决办法

  1. 使用@Getter`` @Setter`` @ToString代替@Data并且自定义equals(Object other) 和 hashCode()方法,比如有些类只需要判断主键id是否相等即足矣。
  2. 或者在使用@Data时同时加上@EqualsAndHashCode(callSuper=true)注解。本文情况因为没有父类,所以这个方法不适用,如果有用到父类的话可以使用。
  3. 如果没有父类的话,使用@DATA同时加上@EqualsAndHashCode(of = {"id"})。指定仅使用id属性,如果有多个可以确定对象唯一的属性的话也可以继续在{}中添加。
  4. 使用@DATA同时加上@EqualsAndHashCode(onlyExplicitlyIncluded = true),然后在需要执行的属性加上@EqualsAndHashCode.Include,如:
/** The unique identifier */
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    @Column(name = UNIQUE_ID_COLUMN_NAME, unique = true, nullable = false)
    @Id
    @EqualsAndHashCode.Include
    private String id;

参考:

https://stackoverflow.com/questions/33893122/jpa-hibernate-find-throws-nullpointerexception.
https://blog.csdn.net/zhanlanmg/article/details/50392266.
http://www.javabyexamples.com/delombok-equalsandhashcode/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值