BigInteger hashcode for embeddable composite key - java

I have a two-column primary key in a database that I need to model with a spring mvc application using hibernate 4.2 and jpa. From what I read online, it seems that my composite key class ConceptPK must include a hashcode method. The problem is that one of the two elements of the primary key is a BigInteger data type, but the default return type of the hashcode() method is int. This is causing eclipse to give an error message below indicating that the program will not compile because I have the wrong return type for the hashcode method.
Do I need a hashcode method? And what do I have to do to the code below to get it to compile with a properly functioning composite key ConceptPK?
import java.io.Serializable;
import java.math.BigInteger;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import org.hibernate.annotations.Type;
import org.joda.time.DateTime;
#Embeddable
class ConceptPK implements Serializable {
#Column(name="id", nullable=false)
protected BigInteger id;
#Column(name="effectiveTime", nullable=false)
#Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
private DateTime effectiveTime;
public ConceptPK() {}
public ConceptPK(BigInteger bint, DateTime dt) {
this.id = bint;
this.effectiveTime = dt;
}
/** getters and setters **/
public DateTime getEffectiveTime(){return effectiveTime;}
public void setEffectiveTime(DateTime ad){effectiveTime=ad;}
public void setId(BigInteger id) {this.id = id;}
public BigInteger getId() {return id;}
public boolean equals(Object o) {
return ((o instanceof ConceptPK) &&
effectiveTime.equals(((ConceptPK)o).getEffectiveTime()) &&
id == ((ConceptPK) o).getId());
}
public int hashCode() {
BigInteger sum = BigInteger.valueOf(
effectiveTime.hashCode()
);
sum.add(id);
return sum;//this line has error message indicating wrong return data type
}
}
Here is the code for the class that uses ConceptPK as its primary key:
#Entity
#Table(name = "tablename")
public class Concept implements Serializable{
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name="id", column=#Column(name="id")),
#AttributeOverride(name="effectiveTime", column=#Column(name="effectiveTime"))
})
private ConceptPK conceptPK;
//lots of other stuff
}

Remember, hash codes don't need to be unique, they just need to be the same for 2 classes containing the same field values.
So why not just add the hashCode's of each field together?:
public int hashCode() {
return id.hashCode() + effectiveTime.hashCode();
}
Of course this doesn't cope with null fields, but I'll leave that up to you. :-)

Always use #Override whenever you are overriding a method of super
class, if you do, compiler will inform you when you do some wrong in
implementation.
The error message wrong return data type which compiler says is correct, your sum is of type BigInteger not Integer.
Integer is a wrapper of the primitive type int. So JVM will perform boxing and unboxing.
BigInteger is a reference type, JVM will not perform boxing and unboxing here.
Solution:
#Override
public int hashCode() {
int hash = 3;
hash = 53 * hash
+ ((effectiveTime == null) ? 0 : effectiveTime.hashCode());
hash = 53 * hash + ((id == null) ? 0 : id.hashCode());
return hash;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final ConceptPK other = (ConceptPK) obj;
if (effectiveTime == null) {
if (other.effectiveTime != null)
return false;
} else if (!effectiveTime.equals(other.effectiveTime))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}

Related

Inserting distinct values from XML into database table

I have XML as follows:
<employee>
<code>13</code>
<label>Admin</label>
</employee>
<employee>
<code>13</code>
<label>Admin</label>
</employee>
<employee>
<code>09</code>
<label>Logistics</label>
</employee>
In my Oracle database, I have 2 columns, namely CODE1, CODE2.
The data should be inserted like CODE1= 13 and CODE2= 09.
But, currently what is happening is that CODE1= 13 and CODE2= 13. And 09 is not been inserted in database.
It just stores the first 2 values ignoring the rest.
My requirement is that, duplicate values must be inserted only once in DB.
Expected result:
CODE1= 13, CODE2= 09
Following is my java code:
for (int i = 0; i < 2; i++) {
final int count = i + 1;
String code = null;
final Emploi[] employee = tabLieuTrav.getEmployee();
code = employee[i].getCode();
if (code != null) {
mapParam.addParamValue(CODE + count,
code);
} else {
mapParam.addParamValue(CODE + count, null,
Types.VARCHAR);
}
getCode() returns the value (e.g. 13) from tag .
Thanks in advance.
try with following solutions,
firstly you should create a Employee class including with hasCode() and equals() methods as follows,
public class Employee {
private int code;
private String lable;
public Employee(int code, String lable) {
super();
this.code = code;
this.lable = lable;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getLable() {
return lable;
}
public void setLable(String lable) {
this.lable = lable;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + code;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (code != other.code)
return false;
return true;
}
}
above hasCode() and equals() methods are generated by eclipse ide. you can creates these methods manually like this,
#Override
public boolean equals(Object obj) {
if (obj instanceof Employee) {
return Objects.equals(code, ((Employee) obj).code);
}
return false;
}
#Override
public int hashCode() {
return this.code;
}
equals Method : Indicates whether some other object is "equal to" this one. for more info
hashCode Method : Returns a hash code value for the object. This method is supported for the benefit of hash tables such as those provided by HashMap. for more info
then, add employee array to ArrayList. because below mentioned methods describe how to get distinct values from ArrayList.
Emploi[] employee = tabLieuTrav.getEmployee();
List<Employee> empList = new ArrayList(Arrays.asList(employee));
then, you can use one of the following methods for remove duplicate values from ArrayList (empList)
method one, remove duplicates from ArrayList using Set (A collection that contains no duplicate elements) for more info
HashSet<Employee> uniqueEmployee = new HashSet(empList);
method two, remove duplicates from ArrayList using java 8 stream distinct method (return distinct element from collection) for more info
List<Employee> uniqueEmployee = empList..stream().distinct().collect(Collectors.toList();
finally, you can use uniqueEmployee collection as follows,
for (Employee employee : uniqueEmployee) {
code = employee.getCode();
if (code != null) {
mapParam.addParamValue(CODE + count, code);
} else {
mapParam.addParamValue(CODE + count, null, Types.VARCHAR);
}
}

How to test the child class for equality in Java?

I am working on a project, but I got stuck in some issue. I need to test equality of child class (DiscountProduct).
Relation between classes can be understood as: Order class has-a Product and Product is parent of DiscountProduct. I want to test DiscountProduct for equality. Any help is much appreciated. Thank you!
Below is the code:
Order Class:
public class Order implements Comparable<Order>{
private int quantity;
//composition has-a relationship
private Product product;
public Order(int quantity, Product product) {
this.quantity = quantity;
this.product = product;
}
public boolean equals(Object obj){
if (obj instanceof Order) {
return product.equals(obj) && quantity == ((Order) obj).quantity;
}
return false;
}
public Product getProduct() {
return product;
}
}
Product class
public class Product implements Comparable<Product> {
private String productCode;
private String description;
private int unitPrice; //pence
public Product(String productCode, String description, int unitPrice) {
this.productCode = productCode;
this.description = description;
this.unitPrice = unitPrice;
}
//equals method to test product for equality.
public boolean equals(Object obj){
if (this == obj){
return true;
}
if (obj == null || !(obj instanceof Product)){
System.out.println("-");
return false;
}
Order other = (Order) obj;
if (!productCode.equals(other.getProduct().getProductCode()))
return false;
if (!description.equals(other.getProduct().getDescription()))
return false;
if (unitPrice != (other.getProduct().getUnitPrice()))
return false;
return true;
}
}
DiscountProduct class
public class DiscountProduct extends Product {
private double discountRate;
public DiscountProduct(String productCode, String description, int unitPrice, double discountRate) {
super(productCode, description, unitPrice);
this.discountRate = discountRate;
}
//equals method to test discount product for equality.
public boolean equals(Object obj){
Order other = (Order) obj;
//how to test for the equality for the discountProduct's field discountRate?
//does I need to add some method in Order class to get the discountRate of object of Order class,
//because relation is 'Order has Product' and then there is a parent-child relation
//between product and DiscountProduct class.
}
}
DiscountProduct could do something like:
#Override // always always always use that annotation when overriding!
public boolean equals(Object obj){
.. this == obj test
if (obj == null || !(obj instanceof DiscountProduct)){
return false;
}
if (super.equals(obj)) {
cast to DiscountProduct and check discountRate
The point here is:
you really only want objects to be equal that are of the same class. Otherwise there is a high chance that you get the necessary if a.equals(b) then b.equals(a) rule wrong
then you want to re-use the existing implementation of the parent class
to then finally, compare the child class field(s)
It might also make sense to declare that "last" version of equals() to be final, but that really depends on context.
In this part of the code:
public class Order implements Comparable<Order>{
...
public boolean equals(Object obj){
if (obj instanceof Order) {
return product.equals(obj) && ...;
}
...
}
}
A Product is comared with an Order. This comparison should obviously return false since a Product is no Order. What you probably meant to write was:
return product.equals(obj.product) && ...;
A remark on your code: There is a contract between Object::equals and Object::hashCode:
The general contract of hashCode is:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.
To conform with this contract, one should always override hashCode() when one overridest equals(...).
I would also encourage you to set methods equals(...) and hashCode() final. Otherwise, the contract of equals(...) could be violated.

Java POJO collection attributes

I have a POJO something like the one mentioned below. Here I'm referring Set collection attribute in POJO1. I understand that set does not contain duplicate. Do I need to override equals() and hashCode() methods in POJO2? Using a Set here is not really going to helpful unless we override equals and hashCode methods? Please help me to understand little bit more on this context!
public class POJO1 {
private String name;
private Set<POJO2> pj2;
public Company(){
pj2 = new HashSet<>();
}
//setter and getter methods
}
Yes the only way for Java to understand which objects are duplicates is to call equals() method. Default implementation of equals() checks that references of two objects point to the same location in memory.
But depending on exact implementation of your Set you might need to override hashCode/equals or implement Comparable interface.
Since you put objects of POJO2 into HashSet you need to verride hashCodeequalsmethods inPOJO2` class.
You do like this
import java.util.Set;
public class POJO1 {
private String name;
private Set<POJO2> pojo2;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<POJO2> getPojo2() {
return pojo2;
}
public void setPojo2(Set<POJO2> pojo2) {
this.pojo2 = pojo2;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
POJO1 pojo1 = (POJO1) o;
if (name != null ? !name.equals(pojo1.name) : pojo1.name != null) return false;
return pojo2 != null ? pojo2.equals(pojo1.pojo2) : pojo1.pojo2 == null;
}
#Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (pojo2 != null ? pojo2.hashCode() : 0);
return result;
}
}
Learn more at https://docs.oracle.com/javase/10/docs/api/java/lang/Object.html#equals(java.lang.Object)

Play 2.0 creating a finder when using a composite (embeded) key: not working correctly

I have a model called Totals
#Entity
public class Totals extends Model{
#EmbeddedId
private TotalsPK id;
public Totals(TotalsPK key, Integer _count)
{
id = key;
count = _count;
}
public static Finder<TotalsPK,Totals> find = new Finder<TotalsPK, Totals> (
TotalsPK.class, Totals.class
);
public static Totals find(TotalsPK id)
{
//try this way instead of relying on find.byId working..... same error though!
return find.where().eq("user_id", id.getUserId()).eq("item_id", id.getItemId()).findUnique();
// return find.byId(id);
}
........... etc
And then I have my key class
#Embeddable
public class TotalsPK {
private Long userId;
private Long itemId;
public TotalsPK(Long _userId, Long _itemId)
{
userId = _userId;
itemId = _itemId;
}
public boolean equals(Object rhs)
{
return (userId.equals(((TotalsPK)rhs).getUserId()) && itemId.equals(((TotalsPK)rhs).getItemId()));
}
public int hashCode()
{
//from Effective Java Chapter 3
int result = (int) (userId ^ (userId >>> 32));
result = 31 * result + (int) (itemId ^ (itemId >>> 32));
return result;
}
This works fine when searching for a record which doesnt exist, but when searching for one that does exist the object passed to "equals" from Ebean is null and I have no idea why this is, any ideas what I am doing wrong here?
Null checking the rhs value passed into equals stops it crashing, but the equals check is never hit
thanks

Overriding equals/hashCode on cross referencing classes in Java causes StackOverflowError

I have two classes that represent two different database entities. Their relationship is 1:m in db and it is represented in class structures something like this:
public class Company {
private List<Employee> employees;
public List<Employee> getEmployees() {
return employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
}
public class Employee {
private Company company;
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
}
Now I want to override equals/hashCode on these classes. Eclipse generates the following code for me:
public class Company {
private List<Employee> employees;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((employees == null) ? 0 : employees.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Company other = (Company) obj;
if (employees == null) {
if (other.employees != null)
return false;
} else if (!employees.equals(other.employees))
return false;
return true;
}
}
public class Employee {
private Company company;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((company == null) ? 0 : company.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (company == null) {
if (other.company != null)
return false;
} else if (!company.equals(other.company))
return false;
return true;
}
}
If I run the following test:
public class EqualsTest {
#Test
public void testEquals() {
Company company1 = new Company();
Employee employee1 = new Employee();
employee1.setCompany(company1);
company1.setEmployees(Arrays.asList(employee1));
Company company2 = new Company();
Employee employee2 = new Employee();
employee2.setCompany(company2);
company2.setEmployees(Arrays.asList(employee2));
assertThat(company1, is(company2));
}
}
I expect it to pass because both company1 and company2 have equal lists of employees, but it fails with StackOverflowError:
java.lang.StackOverflowError
at java.util.AbstractList$Itr.<init>(AbstractList.java:318)
at java.util.AbstractList$Itr.<init>(AbstractList.java:318)
at java.util.AbstractList$ListItr.<init>(AbstractList.java:377)
at java.util.AbstractList.listIterator(AbstractList.java:315)
at java.util.AbstractList.listIterator(AbstractList.java:284)
at java.util.AbstractList.equals(AbstractList.java:502)
at com.test.Company.equals(Company.java:37)
at com.test.Employee.equals(Employee.java:35)
at java.util.AbstractList.equals(AbstractList.java:507)
at com.test.Company.equals(Company.java:37)
at com.test.Employee.equals(Employee.java:35)
at java.util.AbstractList.equals(AbstractList.java:507)
at com.test.Company.equals(Company.java:37)
at com.test.Employee.equals(Employee.java:35)
...
I understand that the reason for this failure is cross reference in classes and thus equals/hashCode methods. But how should I implement equals/hashCode to avoid infinitive recursion?
As it is now, the identity of a company is defined solely by its employees. Likewise, the identity of an employee is defined solely by its company. Do you see how that leads to a mutual logical dependency?
You need to break that logical dependency in your code. How would you logically uniquely identify a company and an employee? Typically you'd do this with some sort of meaningful unique identifier: a name (string), a number (int/long), or some similar combination of primitive fields.
Imho there are 2 versions available. I assume company should be the "leading" class, storing the employees.
version: In the employee equals, use the "==" to check for object equality on company (not very nice)
version: assign your company a unique ID and compare that only that company ID in employee equals
hth
Do not compare the list of employees within the Company.equals method. Are there other attributes of Company that are meaningful and could be used to perform the comparison within equals, like a name? Or Stock Symbol?
You have inadvertently set up a recursive dependency between Company and Employee. The Company#hashCode() method needs to compute the individual hashcodes of every Employee, and the Employee#hashCode() method depends on the Company's hashcode, leading to an infinite recursion.
A company object's hashcode should not depend on the employees in it. The hash code is in some sense the "identity" of the object, which shouldn't change when a new employee is added to it. Same for Employee. The Employee's identity shouldn't change just because he/she moves to a different company.
You'll have to redefine those methods in terms of some meaningful identity attribute. Your code doesn't show it, but both Company and Employee must have some other member variables, such as a name. Base the hashCode and equals implementations on that attribute.

Categories

Resources