Oomph Fortuity
Oomph Fortuity

Reputation: 6118

How to create own Custom Predicate to compare composite id in hazelcast

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?

Upvotes: 0

Views: 1679

Answers (1)

Gokhan Oner
Gokhan Oner

Reputation: 3257

@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.

Upvotes: 4

Related Questions