Java POJO collection attributes - java

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)

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?

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

How to check if a string exists in a object which is stored in a hashmap?

I have created a Employee class with 3 parameters.
Id
Name
Age
Requirement: Search based on Name. This is a case where all employees have a unique name. Its mandatory to add the objects with key as id. There are rare cases where it is required to search based on name.
What i have done :
Within the class I am overriding hashCode and Equals method.
I am adding a list of these objects into the hashmap with id as key and value as Employee object
But while adding or searching from a hashmap both the methods do not get called
So what is the use of these methods in terms on hasmap?
Employee Class
public class Employee {
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int hashCode() {
return name.hashCode();
}
public boolean equals(Employee emp) {
if (emp == null)
return false;
else if (emp.name.equalsIgnoreCase(this.name))
return true;
else
return false;
}
}
Main Method:
public class HashMapTest {
public static void main(String[] args) {
Employee emp1=new Employee();
emp1.setId(1);
emp1.setName("Maclean");
emp1.setAge(24);
Employee emp2=new Employee();
emp2.setId(2);
emp2.setName("Sampath");
emp2.setAge(25);
Employee emp3=new Employee();
emp3.setId(3);
emp3.setName("Achar");
emp3.setAge(27);
Employee emp4=new Employee();
emp4.setId(4);
emp4.setName("Sudheer");
emp4.setAge(25);
Employee emp5=new Employee();
emp5.setId(5);
emp5.setName("Kunder");
emp5.setAge(25);
HashMap<Integer, Employee> empmap=new HashMap();
empmap.put(emp1.getId(), emp1);
empmap.put(emp2.getId(), emp2);
empmap.put(emp3.getId(), emp3);
empmap.put(emp4.getId(), emp4);
empmap.put(emp5.getId(), emp5);
Employee emp=new Employee();
emp.setName("Maclean");
System.out.println(empmap.containsValue(emp));
System.exit(1);
}
}
Update Solution:
Thanks for all the answers.
1. hashCode method gets called only if the Key is a object and the method exists within the Key Class
2. Equals(Employee emp) is causing function overloading instead of overriding. I should have used equals(Object o)
Changes in the code to resolve the issue
#Override
public boolean equals(Object o) {
if (o == null)
return false;
if (!(o instanceof Employee))
return false;
Employee emp = (Employee) o;
if (emp.name.equalsIgnoreCase(this.name))
return true;
else
return false;
}
You are not overriding Object.equals(Object o), which you need to do. You are overloading it. That's why it's not being called.
Try this equals() instead:
public boolean equals(Object o) {
if (o == null)
return false;
if (!(o instanceof Employee))
return false;
Employee emp = (Employee) o;
if (emp.name.equalsIgnoreCase(this.name))
return true;
else
return false;
}
Within the class I am overriding hashCode and Equals method.
[...]
But while adding or searching from a hashmap both the methods do not get called
So what is the use of these methods in terms on hasmap?
If you have a Map<Key, Value>, and you call put or get on that map, then hashCode and equals are called on the Key class, not on the Value class.
In your case, that means that if you do empmap.put(emp1.getId(), emp1); then it checks the hash of emp1.getId() and whether that's already in the map. So it's normal that those methods are not called on your Employee class.
Also, if id is the "unique" attribute, then Employee.hashCode should probably be based on that (and equals, too, to be consistent with hashCode), and as noted in another answer, Employee.equals should accept any Object as parameter.
I did not test, but try it with
HashMap<Integer, Employee> empmap=new HashMap<>();
or even
HashMap<Integer, Employee> empmap=new HashMap<Integer, Employee>();
This can be done very nicely in Java 8 using streams.
empmap.values().stream().anyMatch(emp.getName().equals(searchedName));
This takes the set of all entries in the map and see if the stream matches any entry that has a name equal to your searchedName.
In a comparable you can also fetch all matching names by using Stream.filter()
Implementing a different version of equals/hashcode is tricky because it changes the behavior of the class in many ways.
The easiest solution for your problem is to add this method to the Employee class.
Silently, HashMap uses the equals(Object o) of a value object (in this case Employee) for checking the existence of that object.
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
if (name != null ? !name.equals(employee.name) : employee.name != null) return false;
return true;
}
Be careful, This implementation of equals(Object o) just works on the name and it does not check other fields.
Employee emp=new Employee();
emp.setId(10);
emp.setName("Maclean");
emp.setAge(240);
System.out.println(empmap.containsValue(emp));
System.out.println(emp1.equals(emp));
is
true
true

BigInteger hashcode for embeddable composite key

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;
}

Access to array list many times

I have list (array list)that can contain many instances (between 500-3000 instances ).
during the program some function need to access to this list (many times)and search for specific instance or more ,to get the instance\s they need loop on the list and provide parentName and name (which is string) and are not uniqe key .
my question is since the list need to be accessed many time there is a way to define/design it better that the access to the list can be more efficient?
Please keep in mind that the functions that need to get instance/s from the list
cannot provide full key the can provide only name and parentName which can have more that one instance.
List<Obj> myList = new ArrayList<Obj>();
class obj
{
parentName
Name
type
curr
....
Use a Map<MyEntry, List<Obj>> where MyEntry is a class enclosing parent name and name as such:
public final class MyEntry
{
private final String parentName;
private final String name;
private final int hashCode;
public MyEntry(final String parentName, final String name)
{
this.parentName = parentName;
this.name = name;
hashCode = 31 * parentName.hashCode() + name.hashCode();
}
// Override .equals() and .hashCode()
#Override
public int hashCode()
{
return hashCode;
}
#Override
public boolean equals(final Object o)
{
if (this == o)
return true;
if (o == null)
return false;
if (getClass() != o.getClass())
return false;
final MyEntry other = (MyEntry) o;
return parentName.equals(other.parentName)
&& name.equals(other.name);
}
// Have a nice string representation
#Override
public String toString()
{
return "parent name: " + parentName + ", name: " + name;
}
}
You can, for instance, have a method in your Obj which returns the matching MyEntry object. Also, if you use Guava, have a look at MultiMap.
You will notice that the hash code is precomputed: this can be done since the MyEntry class is immutable. This allows for very fast usage as keys for a Map.
(edit: added .toString())

Categories

Resources