Removing duplicates when parsing Json in JAVA, Hashset not working - java

I've got a problem I am currently tring to parse a Json file and remove duplicate from it so i thought that i would store it in a Hashset of my Class that hold information but it doesnt remove duplicate.
Can you explain me if I did something wrong of if there is something that I don't understand?
here is a sample of my Code:
try {
FileReader f = new FileReader("E:\\JavaDev\\src\\main\\resources\\annonces.json");
JsonReader jsonReader = new JsonReader(f);
Gson gson = new Gson();
Appartement[] res2 = new Appartement[0];
res2 = gson.fromJson(jsonReader, res2.getClass());
Set<Appartement> test = new HashSet<Appartement>(Arrays.asList(res2));
System.out.println(test.size());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
My Appartment look like this:
(getter and setter are removed here to have smaller code)
public class Appartement {
private String id;
private Double surface;
private String marketingType;
private Integer roomCount;
private String propertyType;
private Boolean furnished;
private Boolean newBuild;
private String zipCode;
private Double price;
}
I tried converting my json directly in a Hashset but I've got an error: java.lang.OutOfMemoryError: Java heap space
HashSet<Appartement> mySet = gson.fromJson(jsonReader, HashSet.class);
I verified that there is duplicate in the Json file.
Would apreciate some help here.

You must override equals method of your Appartment class,
See here: Object equal method, if you don't override its default equal method, it actually compared the reference of the object,
public class Appartement {
private String id;
....
#Override
public boolean equals(Object obj) {
if (!(obj instanceof Appartement)) return false;
return this.id.equals(((Appartement)obj.id));
}
#Override
public int hashCode() {
return 123123131311; //replace to your own hashcode.
}
}
Joshua, Effective Java
You must override hashCode() in every class that overrides equals().
Failure to do so will result in a violation of the general contract
for Object.hashCode(), which will prevent your class from functioning
properly in conjunction with all hash-based collections, including
HashMap, HashSet, and Hashtable.

Set<Appartement> test = new HashSet<Appartement>(Arrays.asList(res2));
You must make sure that Apartment's hashcode and equals method are overridden and you return true from equals method for same Appartement. (based on its properties) otherwise Objects.equals will be called

You need to override equals method (requiring appropriate equality checking) and hascode method in your Appartement.class
import java.util.*;
public class HelloWorld{
public static void main(String []args){
System.out.println("Hello World");
Appartement[] res2 = {(new HelloWorld()).new Appartement("1"), (new HelloWorld()).new Appartement("2"), (new HelloWorld()).new Appartement("3"),(new HelloWorld()).new Appartement("1") };
Set<Appartement> test = new HashSet<Appartement>(Arrays.asList(res2));
System.out.println(test.size());
}
public class Appartement {
private String id;
private Double surface;
private String marketingType;
private Integer roomCount;
private String propertyType;
private Boolean furnished;
private Boolean newBuild;
private String zipCode;
private Double price;
public Appartement(String id){
this.id=id;
}
#Override
public boolean equals (Object other)
{
if (!(other instanceof Appartement))
return false;
Appartement ob = (Appartement) other;
return this.id.equals(ob.id) ;
}
#Override
public int hashCode ()
{
return Arrays.hashCode(new String[]{id});
}
}
}

Related

COMPARABLE - How to see if elements from objects are equals?

Im devoloping a program that i put some elements into my object within an ArrayList... this is my code
import java.util.ArrayList;
public class ListaConcepto {
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList<CompararListas> Lista = new ArrayList<CompararListas>();
CompararListas obj1 = new CompararListas("abc", 12.25, "lala", 2);
CompararListas obj2 = new CompararListas("abc", 13.50, "lala", 3);
CompararListas obj3 = new CompararListas("poc", 12.50, "jaja", 1);
Lista.add(obj1);
Lista.add(obj2);
Lista.add(obj3);
}
}
Then... this is my class with the interface Comparable... and i need a method to implement to see if elements are EQUALS then print the result.
public class CompararListas implements Comparable<CompararListas> {
private String referencia;
private double monto;
private String descripcion;
private double NumeroParte;
public CompararListas(String referencia, double monto, String descripcion, double numeroParte) {
this.referencia = referencia;
this.monto = monto;
this.descripcion = descripcion;
this.NumeroParte = numeroParte;
}
public double getMonto() {
return monto;
}
public void setMonto(double monto) {
this.monto = monto;
}
public String getDescripcion() {
return descripcion;
}
public void setDescripcion(String descripcion) {
this.descripcion = descripcion;
}
public double getNumeroParte() {
return NumeroParte;
}
public void setNumeroParte(double numeroParte) {
NumeroParte = numeroParte;
}
public String getReferencia() {
return referencia;
}
public void setReferencia(String referencia) {
this.referencia = referencia;
}
#Override
public int compareTo(CompararListas o) {
// TODO Auto-generated method stub
return 0;
}
}
Remember Comparable is meant to be used to decide the relationship between to items for the purposes of ordering; it's not quite for equality. In fact, there's no requirement that any two comparable items must be equal.
In your case, you may want to order by NumeroParte, which means "Part Number" and seems like a sensible choice. Every type of data has a different way to be organized.
Your method may look something like
public int compareTo(ComprarListas o){
return this.NumeroParte - o.getNumeroParte();
}
Which works because both are integer numbers.
Or the appropriate property of your object - you may want to order based on price instead for instance.
If you want to know just if an object is equal to another you have to implemet the equals method (which doesn't requiere you to declare any interface, every class can do it)
#Override
public boolean equals(Object o) {
CompararListas other = (CompararListas) o;
return ...
}
with this method you can return what makes the two objects equals to you, if you just have to look for referencia.equals(other.referencia) or if you have to compare every property like referencia.equals(other.referencia) && monto == other.monto && ...
But if you want to compare elements in order to do something like ordering them there you have to implement the Comparable interface and implement the compareTo method
#Override
public int compareTo(CompararListas o) {
if (NumeroParte < o.NumeroParte)
return -1;
else if (NumeroParte > o.NumeroParte)
return 1;
return 0;
}
This will make the objects able to compare each other and for example know if one is "smaller" than other according to your criteria (in this example I only used NumeroParte and made it explicit to be easy to understand, but the key is that you can use any criteria you want to compare the objects and if you want order them later).
These are solutions to different problems, you have to identify which one is the better in your case.

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

achieving polymorphism within the parent class by using instanceof to set attribute

I have a parent class called AggDef which is the base type of some child classes (TermAggDef, StatAggDeff etc.). The class is defined below.
I have some code in another class that loops over a list of AggDef objects and get's their types.
protected Map aggregations = new HashMap();
public List<String> getAggregationTypes(){
HashSet<String> aggTypes = new HashSet<String>();
Iterator it = aggregations.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
AggDef aggDef = (AggDef) pair.getValue();
aggTypes.add(aggDef.getType());
}
List<String> retList = new ArrayList<String>();
retList.addAll(aggTypes);
return retList;
}
My Question is, could I achieve this polymorphic assignment of the type attribute in the parent class itself? Because wherever an AggDef object would be used, it would know what specific type it is. My team member said I should implement the setType method in the actual child classes. But I don't think what I have here is wrong. Any help or elaboration on the accuracy of my approach would be very helpful. Thank you in advance.
public abstract class AggDef implements Cloneable {
protected String name;
protected String term;
protected String type;
...
protected List<AggDef> subAggregations;
public void setType(AggDef def){
if(def instanceof TermAggDef){
def.type = "terms";
}
else if (def instanceof StatAggDef){
def.type = "terms_stats";
}
else if (def instanceof RangeAggDef){
def.type = "range";
}
}
public String getType(){
return type;
}
protected AggDef() {
setType(this);
}
protected AggDef(String term) {
this.term = term;
setType(this);
}
protected AggDef(String name, String term) {
this.name = name;
this.term = term;
setType(this);
}
public AggDef(String term, String order, int size, int offset, boolean isAllTerms) {
this.term = term;
this.size = size;
...
setType(this);
}
public AggDef(String name, String term, String order, int size, int offset, boolean isAllTerms) {
this.name = name;
this.term = term;
...
setType(this);
}
}
AggDef only knows about itself and can never know anything about it's children. So when it calls setType(AggDef) the JVM will reference the locally defined method and not the over-riden.
Hopefully, to help further nail the subject in let's say you have:
AggDef aDefObj = new AggDef();
TermAggDef taDefObj = new TermAggDef();
then that means the following:
aDefObj instanceOf AggDef // true
aDefObj instanceOf TermAggDef // false
taDefObj instanceOf AggDef // true
taDefObj instanceOf TermAggDef // true
Check out Oracle's Inheritance doc specifically Casting.

return multiple value from one method

I have a class UserFunction and it have two method getAudioFunction and getPromptFunction with returning String value, my problem is that i want to return both value in one method
how can i able to do that
UserFunction.java
public class UserFunction{
Map<String,PromptBean> promptObject=new HashMap<String,PromptBean>();
Map<String,AudioBean> audioObject = new HashMap<String,AudioBean>();
XmlReaderPrompt xrpObject=new XmlReaderPrompt();
public String getAudioFunction(String audioTag,String langMode )
{
Map<String, AudioBean> audioObject=xrpObject.load_audio(langMode);
AudioBean audioBean=(AudioBean)audioObject.get(audioTag);
String av=StringEscapeUtils.escapeXml(audioBean.getAudio());
return av;
}
public String getPromptFunction(String promptTag,String langMode )
{
Map<String, PromptBean> promptObject=xrpObject.load(langMode);
PromptBean promptBean= (PromptBean)promptObject.get(promptTag);
String pv=StringEscapeUtils.escapeXml(promptBean.getPrompt());
return pv;
}
}
You need to return an object which holds both values. You could create a class for this purpose. The class can have two getter methods for retrieving the values.
It is not possible to return more than one value from a method in java. You can set multiple value into Map or List or create a custom class and can return that object.
public Map<String,String> getAudioAndPromptFunction(String audioTag,String langMode )
{
Map<String,String> map =new HashMap();
...
map.put("audioBean",StringEscapeUtils.escapeXml(audioBean.getAudio()));
map.put("promptBean",StringEscapeUtils.escapeXml(promptBean.getPrompt());
return map;
}
or you can create a custom bean class like.
public class AudioPrompt{
private String audioBean;
private String promptBean;
...
}
public AudioPrompt getAudioAndPromptFunction(String audioTag,String langMode )
{
AudioPrompt audioPrompt =new AudioPrompt();
...
audioPrompt.set(StringEscapeUtils.escapeXml(audioBean.getAudio()));
audioPrompt.set(StringEscapeUtils.escapeXml(promptBean.getPrompt());
return audioPrompt ;
}
You'll need to return an object that includes both of the values. This could be an array with two elements, a Pair<A,B> class (which holds two generic values, typically from some pan-project utility library), or a method-specific class such as:
public class UserFunctionXmlPairing {
public final String audioBeanXml;
public final String promptBeanXml;
}
Create a new class that holds your two strings and return that.
class AudioPromptPair {
private String audio;
private String prompt;
public AudioPromptPair(String audio, String prompt) {
this.audio = audio;
this.prompt = prompt;
}
// add getters and setters
}
You can wrap all the values you wish into a single object and return that:
public class Prompts {
private Map<String, Object> prompts = new HashMap<String, Object>();
public void addPrompt(String name, Object prompt) {
this.prompts.put(name, prompt);
}
public Object getPrompt(String name) {
this.prompts.get(name);
}
}
It's even easier if your AudioBean and PromptBean have a common super class or interface.
My preference would be to lose the "Bean" in your class names. AudioPrompt and TextPrompt would be preferred.

What is the best way to know if all the variables in a Class are null?

This would mean that the class was initialized, but the variables were not set.
A sample Class:
public class User {
String id = null;
String name = null;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
The actual class is huge that I prefer not to check if(xyz == null) for each of the variables.
Another non-reflective solution for Java 8, in the line of paxdiabo's answer but without using a series of if's, would be to stream all fields and check for nullness:
return Stream.of(id, name)
.allMatch(Objects::isNull);
This remains quite easy to maintain while avoiding the reflection hammer.
Try something like this:
public boolean checkNull() throws IllegalAccessException {
for (Field f : getClass().getDeclaredFields())
if (f.get(this) != null)
return false;
return true;
}
Although it would probably be better to check each variable if at all feasible.
This can be done fairly easily using a Lombok generated equals and a static EMPTY object:
import lombok.Data;
public class EmptyCheck {
public static void main(String[] args) {
User user1 = new User();
User user2 = new User();
user2.setName("name");
System.out.println(user1.isEmpty()); // prints true
System.out.println(user2.isEmpty()); // prints false
}
#Data
public static class User {
private static final User EMPTY = new User();
private String id;
private String name;
private int age;
public boolean isEmpty() {
return this.equals(EMPTY);
}
}
}
Prerequisites:
Default constructor should not be implemented with custom behavior as that is used to create the EMPTY object
All fields of the class should have an implemented equals (built-in Java types are usually not a problem, in case of custom types you can use Lombok)
Advantages:
No reflection involved
As new fields added to the class, this does not require any maintenance as due to Lombok they will be automatically checked in the equals implementation
Unlike some other answers this works not just for null checks but also for primitive types which have a non-null default value (e.g. if field is int it checks for 0, in case of boolean for false, etc.)
If you want this for unit testing I just use the hasNoNullFieldsOrProperties() method from assertj
assertThat(myObj).hasNoNullFieldsOrProperties();
How about streams?
public boolean checkFieldsIsNull(Object instance, List<String> fieldNames) {
return fieldNames.stream().allMatch(field -> {
try {
return Objects.isNull(instance.getClass().getDeclaredField(field).get(instance));
} catch (IllegalAccessException | NoSuchFieldException e) {
return true;//You can throw RuntimeException if need.
}
});
}
"Best" is such a subjective term :-)
I would just use the method of checking each individual variable. If your class already has a lot of these, the increase in size is not going to be that much if you do something like:
public Boolean anyUnset() {
if ( id == null) return true;
if (name == null) return true;
return false;
}
Provided you keep everything in the same order, code changes (and automated checking with a script if you're paranoid) will be relatively painless.
Alternatively (assuming they're all strings), you could basically put these values into a map of some sort (eg, HashMap) and just keep a list of the key names for that list. That way, you could iterate through the list of keys, checking that the values are set correctly.
I think this is a solution that solves your problem easily: (return true if any of the parameters is not null)
public boolean isUserEmpty(){
boolean isEmpty;
isEmpty = isEmpty = Stream.of(id,
name)
.anyMatch(userParameter -> userParameter != null);
return isEmpty;}
Another solution to the same task is:(you can change it to if(isEmpty==0) checks if all the parameters are null.
public boolean isUserEmpty(){
long isEmpty;
isEmpty = Stream.of(id,
name)
.filter(userParameter -> userParameter != null).count();
return isEmpty > 0
}
The best way in my opinion is Reflection as others have recommended. Here's a sample that evaluates each local field for null. If it finds one that is not null, method will return false.
public class User {
String id = null;
String name = null;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isNull() {
Field fields[] = this.getClass().getDeclaredFields();
for (Field f : fields) {
try {
Object value = f.get(this);
if (value != null) {
return false;
}
}
catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return true;
}
public static void main(String args[]) {
System.out.println(new User().isNull());
}
}
Field[] field = model.getClass().getDeclaredFields();
for(int j=0 ; j<field.length ; j++){
String name = field[j].getName();
name = name.substring(0,1).toUpperCase()+name.substring(1);
String type = field[j].getGenericType().toString();
if(type.equals("class java.lang.String")){
Method m = model.getClass().getMethod("get"+name);
String value = (String) m.invoke(model);
if(value == null){
... something to do...
}
}
Best for me is
Stream.of(getClass().getDeclaredMethods()).allMatch(Objects::isNull);
It can be used in a custom annotation + annotation processor to automagically define a boolean isNull() method on the annotated classes.
Based on Irkwz's answer, but a different approach:
public class SomeClass{
private String field1;
private String field2;
private ComplexField field3;
private String field4;
private Integer field15;
public boolean isNullAllFields() {
return Stream.of(this.getClass().getDeclaredFields()).anyMatch(element -> (element != null));
}
}
And the end of the day u invoke isNullAllFields method to figure out wheter the object fields are empty.
If you want to do the opposite i.e check if some/all members of class are non-non, the check this answer.
In order to make sure that certain members of the class are always non-null, we can use lombok #NonNull annotation on the individual fields of the class.
import lombok.Data;
import lombok.NonNull;
#Data
public class DataClass {
#NonNull
private String data1;
private int data2;
#NonNull
private String data3;
#NonNull
private String data4;
#NonNull
private String data5;
private String data6;
DataClass(String data1,...) {
// constructor
}
}
Easiest way is to convert the class to a map and get its keys and with stream check if any or all key's values are null or not, you can take input from user as well whether they want to check for specific set of keys only!
Below is the code to check whether any of the key's value has null, you can change stream config to all match or any match as per your requirement
Just replace isNullOrEmpty method i have used with proper null or empty check condition for that particular collection
public boolean checkIfAnyFieldIsNull(Object instance, Set<String> fields){
try {
Map<String, Object> instanceMap = new Gson().fromJson(new GsonBuilder().serializeNulls().create().toJson(instance), Map.class);
if(!isNullorEmpty(instanceMap)) {
fields = isNullorEmpty(fields) ? instanceMap.keySet() : fields;
return fields.stream().anyMatch(curField -> isNull(instanceMap.get(curField)));
}else{
return false;
}
}catch (Exception e){
return false;
}
}
}
Try this method once, its works for me!!
private fun checkIfAnyDataIsNull(model: YourModelCass): Boolean {
return Stream.of<Any>(
model.date,
model.merchantName,
model.payment,
).allMatch(Objects::isNull)
}
You can use the simple solution:
if(user.equals(new User()){
//your processing goes here
}

Categories

Resources