I'm trying to add an index where my override equals() determines if two objects are the same or not.
Car.java
public static class Car {
final String id;
private String name;
public Car(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static final Attribute<Car, Car> CAR = new SimpleAttribute<Car, Car>() {
#Override
public Car getValue(Car car, QueryOptions queryOptions) {
return car;
}
};
#Override
public String toString() {
return "Car{" + "id=" + id + ", name=" + name + '}';
}
}
Fetcher.java
public static final ResultSet<Car> get(final IndexedCollection<Car> indexedCollection, final Car car) {
return indexedCollection.retrieve(QueryFactory.equal(Car.CAR, car));
}
Main.java
public static void main(String args[]) {
IndexedCollection<Car> cars = new ConcurrentIndexedCollection<>();
cars.addIndex(NavigableIndex.onAttribute(Car.CAR));
}
The problem is on this line cars.addIndex(NavigableIndex.onAttribute(Car.CAR)); where the error message is no suitable method found for onAttribute(Attribute<Car,Car>). Am I doing something wrong here or is there another call I should be using instead?
Remove cars.addIndex(NavigableIndex.onAttribute(Car.CAR));, because it is not really an usefull index... and I think this was not a motivation of the developer. You should create Attributes for CAR_ID and CAR_NAME and create an Query for comparison. In this case I misuse (to achieve what you expect) IndexedCollection as a simple Set. But... here is a possible solution, if I have understood you correctly:
Override equals in Car:
class Car {
private final int id;
private String name;
public Car(int i, String name) {
this.id = i;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public boolean equals(Object obj) {
if(this == obj) return true;
if(obj == null) return false;
if (!(obj instanceof Car)) return false;
Car car = (Car) obj;
if(car.getId() == this.getId())
if(car.getName().equals(this.getName()))
return true;
return false;
}
public static final Attribute<Car, Car> CAR = new SimpleAttribute<Car, Car>() {
#Override
public Car getValue(Car car, QueryOptions queryOptions) {
return car;
}
};
#Override
public String toString() {
return "Car{" + "id=" + id + ", name=" + name + '}';
}
}
Main:
IndexedCollection<Car> cars = new ConcurrentIndexedCollection<>();
cars.add(new Car(1, "test"));
cars.add(new Car(2, "test2"));
cars.add(new Car(3, "test3"));
Car s = new Car(2, "test2");
ResultSet<Car> cs= cars.retrieve(QueryFactory.equal(Car.CAR, s));
cs.forEach(c -> System.out.println(c.toString()));
Related
I have an issue. I created the class "User" and in the constructor, I put the name which I have to write and the id which should be generated when I create an object. Unfortunately, I have created one object and every time when I run the code the UUID is changing the id. How can I write the code in the constructor to create one object ID which will not be changing every run?
public class User {
private String name;
private UUID id;
public User(String name) {
this.name = name;
this.id = UUID.randomUUID();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return String.valueOf(id);
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(name, user.name) && Objects.equals(id, user.id);
}
#Override
public int hashCode() {
return Objects.hash(name, id);
}
#Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id='" + id + '\'' +
'}';
}
};
public class App {
public static void main(String[] args) {
User jan = new User("Jan");
System.out.println(jan);
}
The output:
User{name='Jan', id='089fb1bf-fc15-4af6-b8e9-0d9e88aaa392'}
User{name='Jan', id='24a4214c-f9b2-49b5-ae27-0c41edcaf5b1'}
From the comments, the problem is due to the fact that you're creating a new random UUID in your constructor:
public User(String name) {
this.name = name;
this.id = UUID.randomUUID();
}
To fix the randomness of the identifier, I would suggest adding the UUID as part of the constructor:
public User(UUID id, String name) {
this.id = id;
this.name = name;
}
This way, you can always control the value of the identifier used.
In the long run, depending on how you architect your application, that identifier could come from a Factory object or a database.
So i have 2 classes, and in the class race i have a method ( public Athlete getAthlete(int codAthlete) ) that
should return the object corresponding to the Athlete with the code passed by parameter, but i am not sure how to
implement it. Can someone give me a hand?
public class Athlete {
private int codAthlete;
private String name;
public Athlete(int codAthlete){
this.codAthlete = codAthlete;
}
public int getCodAthlete() {
return this.codAthlete;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public String getInformation() {
return "Code: " + this.codAthlete +
" Name " + this.name;
}
}
.
public class Race {
private String idRace;
private Set<Athlete> athletes;
public Race(String idRace) {
athletes = new HashSet<>();
this.idRace = idRace;
}
public String getIdRace () {
return this.idRace;
}
public Athlete getAthlete(int codAthlete){
for(Athlete a: Athlete){
if(a.getCodAthlete() == codAthlete)
a.getInformation();
}
return (????);
// Returns the object corresponding to the Athlete with the code passed by parameter.
}
}
I have an below object
class CustomObj{
private String name;
private String dept;
public String getName(){
return this.name;
}
public String getDept(){
return this.dept;
}
private CustomObj(){
}
private CustomObj(CustomObjBuilder builder){
this.name = builder.name;
this.dept= builder.dept;
}
#Override
public boolean equals(Object o) {
if (o == this) return true;
if (o == null || getClass() != o.getClass()) return false;
CustomObj that = (CustomObj) o;
return that.name.equals(name) &&
that.dept.equals(dept);
}
#Override
public int hashCode() {
int result = 31;
result = 31 * result + name.hashCode();
result = 31 * result + dept.hashCode();
return result;
}
public static class CustomObjBuilder{
private String name;
private String dept;
public CustomObjBuilder(String name, String dept){
this.name = name;
this.dept = dept;
}
public CustomObjBuilder setName(String name){
this.name = name;
return this;
}
public CustomObjBuilder setDept(String dept){
this.dept = dept;
return this;
}
public CustomObj build(){
return new CustomObj(this);
}
}
}
and class that uses above
class XYZ{
Set<CustomObj> obj = new HashSet<CustomObj>();
public void process(String a, String b){
CustomObj o = new CustomObj.CustomObjBuilder(a,b).build();
if(!obj.contains(o)){
obj.add(o);
}
}
}
And a test class
class TestXYX{
#Test
public void test(){
XYZ xyz = new XYZ();
xyz.process("TEST","TESTABC");
xyz.process("TEST","TESTABC");
}
}
Beacuse I have overrideen hascode and equals, both the above are equal and when process is called second time, the control should not go into if(!obj.contains(o)) second time and size of the set should be 1. But when i run the test obj.add(o); is called two times. But the values of both this object and that objec inside equals methods are same, but
that.name.equals(name) && that.dept.equals(dept)
inside CustomObj returns false. Can someone please help me understand why?
The code is fine. To verify add an sysout to check Set size:
class XYZ {
Set<CustomObj> obj = new HashSet<CustomObj>();
public void process(String a, String b) {
CustomObj o = new CustomObj.CustomObjBuilder(a, b).build();
if (!obj.contains(o)) { // Fails second time for your use case.
obj.add(o);
}
System.out.println(obj.size()); // This is 1 in your use case.
}
}
This is my Car class:
public class Car {
private int FGNr;
private String name;
private String type;
private Owner owner;
private static ArrayList<Integer> allCarIds = new ArrayList<>();
public Car(int FGNr, String name, String type, Owner o) throws Exception {
setFGNr(FGNr);
setName(name);
setType(type);
setOwner(o);
}
public int getFGNr() {
return FGNr;
}
public void setFGNr(int FGNr) throws Exception{
this.FGNr = FGNr;
if(allCarIds.contains(this.FGNr))
throw new Exception("FGNr already excists!! ");
allCarIds.add(this.FGNr);}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Owner getOwner() {
return owner;
}
public void setOwner(Owner owner) throws Exception{
owner.addCar(this);
this.owner = owner;
}
#Override
public int hashCode() {
int hash = 7;
hash = 73 * hash + this.FGNr;
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 Car other = (Car) obj;
if (this.FGNr != other.FGNr) {
return false;
}
return true;
}
#Override
public String toString() {
return "Car{" + "FGNr=" + FGNr + ", name=" + name + ", type=" + type + ", owner=" + owner + '}';
}
}
And this is my Owner class:
public class Owner {
private String SVNr;
private String name;
HashSet<Car> allCars = new HashSet<>();
private static ArrayList<String> allOwnerSVNs = new ArrayList<>();
public Owner(String SVNr, String name) throws Exception{
setSVNr(SVNr);
setName(name);
}
public void addCar(Car c) throws Exception{
if(allCars.contains(c))
throw new Exception("this user has already this car");
if(c.getOwner()!=null)
throw new Exception("this car belongs to other owner");
c.setOwner(this);
allCars.add(c);
}
public String getSVNr() {
return SVNr;
}
public void setSVNr(String SVNr) throws Exception{
this.SVNr = SVNr;
if(allOwnerSVNs.contains(this.SVNr))
throw new Exception("SVNg already excists!! ");
allOwnerSVNs.add(this.SVNr);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public HashSet<Car> getAllCars() {
return allCars;
}
#Override
public int hashCode() {
int hash = 5;
hash = 41 * hash + Objects.hashCode(this.SVNr);
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 Owner other = (Owner) obj;
if (!Objects.equals(this.SVNr, other.SVNr)) {
return false;
}
return true;
}
#Override
public String toString() {
return "Owner{" + "SVNr=" + SVNr + ", name=" + name + ", allCars=" + allCars + '}';
}
}
And this is my main:
try {
Owner o1 = new Owner("0001","Owner1");
Owner o2 = new Owner("0002","Owner2");
Car c1 = new Car(1,"Model S", "Tesla",o1);
Car c2 = new Car(2,"Model 3", "Tesla",o2);
Car c3 = new Car(3,"TT", "Audi",o2);
} catch (Exception ex) {
System.out.println("error:"+ex.getMessage());
}
So when trying to create a new Car I get this error:
Exception in thread "main" java.lang.StackOverflowError
at java.util.HashMap.containsKey(HashMap.java:595)
at java.util.HashSet.contains(HashSet.java:203)
at pkgData.Owner.addCar(Owner.java:28)
at pkgData.Car.setOwner(Car.java:63)
...........
It is a recursion error, but I don't know how to fix it. If I create a new car obviously I have to add the Car to the owner arrayList of cars. and if I call the addCar function the function calls the getOwner function. It's an endless circle of calling.
How I can make sure that when creating a new car that the collection of the owner will also be changed. It would not make any sense that a car has an owner but the owner of the car does not the car in his collection.
These two functions fall an infinite loop as you see.
In Car class
public void setOwner(Owner owner) throws Exception{
owner.addCar(this);
this.owner = owner;
}
And in Owner Class
public void addCar(Car c) throws Exception{
if(allCars.contains(c))
throw new Exception("this user has already this car");
if(c.getOwner()!=this && c.getOwner()!=null)
throw new Exception("this car belongs to other owner");
c.setOwner(this);
allCars.add(c);
}
The car sets its owner and sends itself to the Owner class' addCar() method, thats OK. However, why the Owner class' addCar() method sets the owner as itself again ?
I think there is a logical mistake. If you remove c.setOwner(this) line, it works fine.
Usually adding element to a container should be done in the container itself.
In you example Owner is the container and Car is the element.
As an example see java.awt.Container and java.awt.Component.
Don't call owner.addCar(this); from the Car.setOwner.
Let the Owner add the car to the list (which you already do) and set itself as owner to the Car.
public void setOwner(Owner owner) throws Exception{
owner.addCar(this); //remove this line
this.owner = owner;
}
I want to create my own custome predicate to compare composite id's inside object. The need is to because i have to write specific date comparison logic on object inside object (composite id). I don't want to compare individual attributes.i want to use composite id because it comes from invoker and I can't get result using Predicate.in and Predicate.equals
My Object structure is like below
Birth{id=BirthId{name='b3', dob=Wed Jan 01 10:53:20 IST 1902}, name='b3', dob=Wed Jan 01 10:53:20 IST 1902, description='MNP'}
and inside IMap it is stored like below
key : BirthId{name='b3', dob=Wed Jan 01 10:53:20 IST 1902}
value : Birth{id=BirthId{name='b3', dob=Wed Jan 01 10:53:20 IST 1902}, name='b3', dob=Wed Jan 01 10:53:20 IST 1902, description='MNP'}
My Java Classes(Birth and Birthid) Structure is below
public class Birth implements Serializable, Portable {
private static final long serialVersionUID = 1L;
private BirthId id;
private String name;
private Date dob;
private String description;
public BirthId getId() {
return id;
}
public void setId(BirthId id) {
this.id = id;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getDob() {
return dob;
}
public void setDob(Date dob) {
this.dob = dob;
}
public int hashCode() {
return (new HashCodeBuilder()).append(this.id).append(this.name).append(this.dob).toHashCode();
}
public boolean equals(Object other) {
if (other == this) {
return true;
} else if (!(other instanceof Birth)) {
return false;
} else {
Birth rhs = (Birth) other;
return (new EqualsBuilder()).append(this.id, rhs.id).append(this.name, rhs.name).append(this.dob, rhs.dob).isEquals();
}
}
#Override public String toString() {
return "Birth{" + "id=" + id + ", name='" + name + '\'' + ", dob=" + dob + ", description='" + description + '\'' + '}';
}
public int getFactoryId() {
return 1;
}
public int getClassId() {
return 1;
}
public void writePortable(PortableWriter portableWriter) throws IOException {
portableWriter.writePortable("idComposite", getId());
portableWriter.writeUTF("id", getId().toString());
portableWriter.writeUTF("name", getName());
portableWriter.writeUTF("description", getDescription());
Date date = getDob();
portableWriter.writeLong("dob", ((date == null) ? -1 : date.getTime()));
}
public void readPortable(PortableReader portableReader) throws IOException {
setId((BirthId) portableReader.readPortable("idComposite"));
setName(portableReader.readUTF("name"));
setDescription(portableReader.readUTF("description"));
long date = portableReader.readLong("dob");
setDob(((date == -1) ? null : new Date(date)));
}
}
public class BirthId implements Comparable<BirthId>, Serializable, Portable {
private static final long serialVersionUID = 1L;
private String name;
private Date dob;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getDob() {
return dob;
}
public void setDob(Date dob) {
this.dob = dob;
}
public int hashCode() {
return (new HashCodeBuilder()).append(this.name).append(this.dob).toHashCode();
}
public boolean equals(Object other) {
if (other == this) {
return true;
} else if (!(other instanceof BirthId)) {
return false;
} else {
BirthId rhs = (BirthId) other;
return (new EqualsBuilder()).append(this.name, rhs.name).append(this.dob, rhs.dob).isEquals();
}
}
public int compareTo(BirthId rhs) {
return this == rhs ? 0 : (null == rhs ? -1 : (new CompareToBuilder()).append(this.name, rhs.name).append(this.dob, rhs.dob).toComparison());
}
#Override public String toString() {
return "BirthId{" + "name='" + name + '\'' + ", dob=" + dob + '}';
}
public int getFactoryId() {
return 1;
}
public int getClassId() {
return 2;
}
public void writePortable(PortableWriter portableWriter) throws IOException {
portableWriter.writeUTF("name", getName());
Date date = getDob();
portableWriter.writeLong("dob", ((date == null) ? -1 : date.getTime()));
}
public void readPortable(PortableReader portableReader) throws IOException {
setName(portableReader.readUTF("name"));
long date = portableReader.readLong("dob");
setDob(((date == -1) ? null : new Date(date)));
}
public static ClassDefinition getClassDefinition(int portableVersion) {
ClassDefinitionBuilder result = new ClassDefinitionBuilder(1, 2, portableVersion);
result.addUTFField("name");
result.addLongField("dob");
return result.build();
}
}
I have created own custom Predicate to compare dates like below
public class DatePredicate extends AbstractPredicate<Comparable, BirthId> {
Comparable[] values;
private volatile Set<Comparable> convertedInValues;
public DatePredicate() {
}
public DatePredicate(String attribute, Comparable... values) {
if (values == null) {
throw new NullPointerException("Array can't be null");
} else {
this.values = values;
}
}
protected boolean applyForSingleAttributeValue(Map.Entry entry, Comparable attributeValue) {
//My own date comparison logic
return true;
}
public int getId() {
return 99;
}
}
Caller code is
Predicate p = new DatePredicate("id", new BirthId("12345",passSpecifiedDate()));
Result res = imap.values(p);
I am getting below error
Exception in thread "main" com.hazelcast.nio.serialization.HazelcastSerializationException: com.hazelcast.internal.serialization.impl.ArrayDataSerializableFactory#5f007be3 is not be able to create an instance for id: 99 on factoryId: -32
I do not know the best way to create own custom predicate and hazelcast doc does not specify the also.
Could any please guide me how to do this?
#oomph-fortuity, your DatePredicate extends AbstractPredicate which implements IdentifiedDataSerializable and used by built-in Hazelcast predicates. Built-in Predicate Serializable Factory try to deserialize your class & fails since it only knows how to serialize/deserialize built-in Predicates.
Instead, just implement com.hazelcast.query.Predicate interface:
class DatePredicate implements Predicate<BirthId, Birth> {
BirthId birthIdToCompare;
public DatePredicate() {
}
public DatePredicate(BirthId birthId) {
this.birthIdToCompare = birthId;
}
#Override
public boolean apply(Map.Entry<BirthId, Birth> mapEntry) {
BirthId key = mapEntry.getKey();
///your custom logic
return true;
}
}
And call like this
Predicate p = new DatePredicate(new BirthId("12345",passSpecifiedDate()));
Result res = imap.values(p);
Let me know if that works.