How to test the child class for equality in Java? - 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.

Related

How to compare sets without comparing the content

So, I have two Sets with elements of my class Capability.
public class Capability {
private String name;
public Capability(){
//
}
public Capability(String name){
this.name = name;
//this.id = count.getAndIncrement();
}
public String getName(){
return name;
}
#Override
public String toString(){
return "Capability: "+name+".";
}
}
Please disregard the value of this class over a String, this is for future expansion.
I'm trying to compare two sets that I've gotten from importing a json file, so they are not the same object, nor contain the same object, just have the same content.
public boolean allCapabilitiesMet(){
int count = 0;
for(Capability taskCap : this.getReqCapabilities()){
for(Capability primCap : this.getPrimitive().getCapabilities())
{
System.out.println(taskCap.equals(primCap));
System.out.println(taskCap.getName().equals(primCap.getName()));
if(taskCap.equals(primCap)){
count++;
}
}
}
return count == this.getReqCapabilities().size();
//return this.getPrimitive().getCapabilities().containsAll(this.getReqCapabilities());
}
The goal is to see if one set is a subset of the other, which I could do with the commented return before I switched to importing from the json file.
The thing is, I could fix this right now by simply changing the if clause to the string comparison, because that does indeed work. This would be terrible once I start adding other fields to the main class.
Is there anything I can do to compare the sets content without manually checking their content?
So I just replaced the equals() and hashCode() methods in Capability after adding an id field.
#Override
public boolean equals(Object obj){
if(this == obj)
return true;
if(obj == null || obj.getClass() != this.getClass())
return false;
Capability cap = (Capability) obj;
return (cap.getName().equals(this.getName()) && cap.getId() == this.getId());
}
#Override
public int hashCode()
{
return (int) this.id;
}
With this, I can use the solution that I'd originally planned for the comparison
public boolean allCapabilitiesMet(){
return this.getPrimitive().getCapabilities().containsAll(this.getReqCapabilities());
}
Is there any issue with this implementation? Sadly, I'll have to add a term to the if statement everytime I want to add a field to Capability. Is there any other way?

Search an ArrayList with multiple fields using only one field from a different ArrayList

If there is an ArrayList for moviesAvailable and the list takes title, year, genre, price. How can I get a list of movies using an ArrayList of genres?
There is a toString method in the Movie class that prints out the movies. When I run the code everything past the if statement doesn't run because the condition is returned as false.
You need to override equals() in your Genre class, so that you can compare instances of that class to each other.
Here's a quick implementation, which can easily be extended for additional functionality:
#Override
public boolean equals(Object o) {
if (!(o instanceof Genre)) {
return false;
}
return ((Genre) o).name.equals(this.name);
}
You need to override equals method in Genre class to make if condition working, see below code
private String name;
Genre(String name){
this.name = name;
}
public boolean hasType(String genre) {
return genre.equals(this.name);
}
public boolean equals(Object o) {
if (!(o instanceof Genre)) {
return false;
}
return this.name.equals(((Genre)o).name);
}

Java compare the elements of a class

I have a class name "Users" and have 2 elements (int)userId and (String)userName.
Let's said
Users obj1 = new Users(10, "User1");
Users obj2 = new Users(11, "User2");
So I want to compare obj1 to obj2
element by element
10 compare to 11,
"User1" compare to "User2".
From the research i do from web. It looks like impossible to do it whether convert it to 2d array to compare or whatever method. Is there any method to do this kind of things?
I actually want to do an audit trail so i have the object before changes and after changes, so whatever element that have changed will insert a new record in the audit_trail table with the before value and after value.
I'm a newbie to programming i tried my best to think a way but it just doesn't work. Is there any other way of doing this by SQL? i using ng-admin as (front-end) and API java http to do a update (back-end).
You need to implement the Comparable<Users> interface. If you want equality check too, then you have to override
boolean equals(Object)
and
int hashCode()
Read:
https://docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html
and
Why do I need to override the equals and hashCode methods in Java?
From your question, We can compare two different objects.
Please implement the equals method to do your operations available in Comparable<Users>.
Let's say as a example below,
Class obj1 = new Class(1, "raja");
Class obj2 = new Class(2, "thiru");
The id and name are a public variable of the class. Then
override the function as,
public boolean equals(Object obj)
{
return (this.id == obj.id && this.name.equals(obj.name.equals));
}
Thanks.
You should override the .equals() method, making your Users class as follows:
public class Users {
private int mId;
private String mName;
public Users(int pId, String pName) {
mId = pId;
mName = pName;
}
public int getId() {
return mId;
}
#Override
public boolean equals(Object pObject) {
return (pObject instanceof Users && ((Users) pObject).getId() == mId);
}
}
I'd probably create a BeanDelta object
public class PropertyDelta {
private String propertyName;
private Object value1;
private Object value2;
// constructor & getters
}
public class BeanDelta<T> {
private Class<T> type;
private List<PropertyDelta> propertyDeltas = new ArrayList<>();
public BeanDelta(Class<T> type) {
this.type = type;
}
// getters
}
Then you could write a reflection based method
public <T> BeanDelta<T> getDelta(T o1, T, o2) {
Class<T> type = o1.getClass();
Method[] methods = type.getMethods();
BeanDelta<T> delta = new BeanDelta<>(type);
for (Method meth : methods) {
boolean isGetter = method.getParameterTypes().length == 0 && !method.getReturnType().equals(void.class) && meth.getName().startsWith("get");
if (isGetter) {
Object v1 = meth.invoke(o1);
Object v2 = meth.invoke(o2);
if (!Objects.equal(v1, v2)) {
String propertyName = meth.getName().substring(3);
delta.propertyDeltas.add(new PropertyDelta(propertyName, v1, v2));
}
}
}
return delta;
}
Check it out the solution proposed for do that.
http://www.codejava.net/java-core/collections/sorting-a-list-by-multiple-attributes-example

Apache Commons Lang3 Hashcode, Equals and ToString including Enums

We have few datatypes defined for our service response and request objects in a model. Recently we found a need of implementing ToString, HashCode and Equals on all such types to make use of these over comparison and assertions. Confirming from few source like What issues should be considered when overriding equals and hashCode in Java?, Right way to implement equals contract etc we followed implementing toString, equals and hashcode using org.apache.commons.lang3.builder.EqualsBuilder, HashCodeBuilder and ToStringBuilder as follows -
Response.java
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
public class Response {
private Integer value;
private Currency currency;
private Object edited;
public Response() {
}
public Response(Integer value, Currency currency, Object edited) {
this.value = value;
this.currency = currency;
this.edited = edited;
}
public Currency getCurrency() {
return currency;
}
public void setCurrency(Currency currency) {
this.currency = currency;
}
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
public Object getEdited() {
return edited;
}
public void setEdited(Object edited) {
this.edited = edited;
}
#Override public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Response Response = (Response) o;
return new EqualsBuilder().append(value, Response.value).append(currency, Response.currency)
.append(edited, Response.edited).isEquals();
}
#Override public int hashCode() {
return new HashCodeBuilder(17, 37).append(value).append(currency).append(edited).toHashCode();
}
#Override public String toString() {
return "Response{" + "value=" + value + ", currency=" + currency + ", edited=" + edited + '}';
}
}
Currency.java
public enum Currency {
INR
}
On implementing these using the default library version, there is a thought around enums that comes to our mind -
Is it correct to use the default hashcode and equals from the library when a datatype might contain parameters including enums as well?
Is there a library(within commons would be great) support to implementing a correct optimized solution to overriding implementation of hashcode and equals?
On a side note does the library implementation needs an improvement here or is it correct to what exists?
Edit: Have added the implementation over an Object field(edited) in the class as well. The concern there being same if I override the hashCode and equals implementation for these as well.
Do I end up using an Object's hashcode which is different for different instances as it is mostly the memory mapped address?
Edit 2: I can also see a concern raised on the inconsistent implementation on HashCode for Enum values on JIRA

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