Issue
I am having two entities Country
and State
@Getter @Setter //@EqualsAndHashCode(doNotUseGetters=true)
@Entity
@Table(name = "country", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }) })
public class Country {
@Id
@Column(name = "country_id")
private int countryId;
@Column(name = "name", length = 45)
private String name;
@Column(name = "phonecode", length = 45)
private int phoneCode;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "country")
private Set<State> states;
}
@Getter @Setter // @EqualsAndHashCode(doNotUseGetters=true)
@Entity
@Table(name = "state")
public class State {
@Id
@Column(name = "state_id")
private int stateId;
@Column(name = "name", length = 45)
@NotBlank
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "country_id", nullable = false)
private Country country;
}
I am using Spring-boot so a test I wrote to get cities of a country
@Autowired
private CountryDao countryDao;
@Test
@Transactional
public void getAllStateWithCountryName() {
Country country = countryDao.findById(101).orElseThrow(() -> new EntityNotFoundException());
System.out.println("country: " + country.getName());
country.getStates().forEach((state) -> {
System.out.println("state: " + state.getName());
});
}
The moment I uncomment the @EqualsAndHashCode(doNotUseGetters=true)
, the mapping behave in the EAGER
way and even it goes to the StackOverFlowError
. Earlier I was guessing that somewhere in the equals()
or hashcode()
the getStates()
is getting called(making it look like EAGER
loading) but since I was using doNotUseGetters=true
flag that made me sure that getter is not in the issue. Then I looked at the generated code by lambok
and the culprit was not the getter, but the use of the cities
collection inside the hashcode()
implementation.
The generated hashCode()
public int hashCode()
{
int PRIME = 59;
int result = 1;
result = result * 59 + this.stateId;
Object $name = this.name;
result = result * 59 + ($name == null ? 43 : $name.hashCode());
Object $cities = this.cities;
result = result * 59 + ($cities == null ? 43 : $cities.hashCode()); //problem here
return result;
}
The problem lies at the $cities.hashCode()
. If I comment out this use of $cities
, everything works fine.
So, should I implement my own(not using Lombok
) implementation of hashCode()
keeping the cities
out? Would that be the right implementation?
The logs:
Hibernate: select country0_.country_id as country_1_12_0_, country0_.name as name2_12_0_, country0_.phonecode as phonecod3_12_0_ from country country0_ where country0_.country_id=?
country: India
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
Hibernate: select states0_.country_id as country_3_38_0_, states0_.state_id as state_id1_38_0_, states0_.state_id as state_id1_38_1_, states0_.country_id as country_3_38_1_, states0_.name as name2_38_1_ from state states0_ where states0_.country_id=?
......................until stackoverlow error
Solution
You can still use Lombok
and exclude the lazily fetched collection from the hashcode
method generated, you just need to add the annotation @EqualsAndHashCode.Exclude
to your collection as shown below.
@EqualsAndHashCode.Exclude
private Set<State> states;
Answered By - Ahmed Abdelhady
Answer Checked By - Clifford M. (JavaFixing Volunteer)