Creating immutable view of object using Proxy classes - java

I'm newest at using Proxy classes. I need to create fabric method of immutable view for my object (MusicalInstrument.class)
View must throw an Exception when i'm trying to invoke setter and invoking of other methods must transfer to my object.
Maybe you have got some examples or sources where i can find answers! Thanx!
public class MusicalInstrument implements Serializable {
/**
* ID of instrument.
*/
private int idInstrument;
/**
* Price of instrument.
*/
private double price;
/**
* Name of instrument.
*/
private String name;
public MusicalInstrument() {
}
public MusicalInstrument(int idInstrument, double price, String name) {
this.idInstrument = idInstrument;
this.price = price;
this.name = name;
}
public int getIdInstrument() {
return idInstrument;
}
public void setIdInstrument(int idInstrument) {
this.idInstrument = idInstrument;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MusicalInstrument that = (MusicalInstrument) o;
if (idInstrument != that.idInstrument) return false;
if (Double.compare(that.price, price) != 0) return false;
return name != null ? name.equals(that.name) : that.name == null;
}
#Override
public int hashCode() {
int result;
long temp;
result = idInstrument;
temp = Double.doubleToLongBits(price);
result = 31 * result + (int) (temp ^ (temp >>> 32));
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}
#Override
public String toString() {
return "MusicalInstrument{" +
"idInstrument=" + idInstrument +
", price=" + price +
", name='" + name + '\'' +
'}';
}

You can use ImmutableProxy of the reflection-util library.
Example:
MusicalInstrument instrument = new MusicalInstrument(1, 12.5, "Guitar");
MusicalInstrument immutableView = ImmutableProxy.create(instrument);
assertThat(immutableView.getName()).isEqualTo("Guitar");
// throws UnsupportedOperationException
immutableView.setName(…);

Related

How do I generate objects randomly in java?

I have an abstract class called "Student" and 2 subclasses "Graduate" and "Undergraduate", they both have the same parameters.
I want to create 10 Student objects randomly, some from the "Graduate" and some from the "Undergraduate" classes.
I want to print the displayStudent() method for all objects created, I got stuck on how to randomly generate the 10 students so they are all random of type graduates and undergraduates.
public abstract class Student {
private int ID;
private double GPA;
public Student(int ID, double GPA) {
this.ID = ID;
this.GPA = GPA;
}
public int getID() {
return ID;
}
public double getGPA() {
return GPA;
}
public abstract String getLevel();
public abstract String getStatus();
public final String displayStudent() {
return getLevel() + " ID>> " + getID() + ", GPA>> " + getGPA() + ", Status>> " + getStatus();
}
}
public class Graduate extends Student{
public Graduate(int ID, double GPA) {
super(ID, GPA);
}
#Override
public String getLevel() {
return "graduate";
}
#Override
public String getStatus() {
if( getGPA() >= 3) {
return "honor";
} else if (getGPA() >= 2 && getGPA() <= 3) {
return "good";
} else {
return "probation";
}
}
}
public class Undergraduate extends Student {
public Undergraduate(int ID, double GPA) {
super(ID, GPA);
}
#Override
public String getLevel() {
return "undergraduate";
}
#Override
public String getStatus() {
if( getGPA() >= 3) {
return "honor";
} else if (getGPA() >= 2 && getGPA() <= 3) {
return "good";
} else if( getGPA() > 0 && getGPA() < 2) {
return "probation";
} else {
//for any number that is not in the range of the GPA
return "invalid GPA!";
}
}
}
Try this.
using the ternary operator ?: is key.
exp ? a : b says if exp is true, do a, else do b
I used the loop index+1 as the id.
If the boolean is true, graduate, otherwise undergrad.
The double is multiplied by 4 to get the GPA.
Random r = new Random();
List<Student> students = new ArrayList<>();
for (int i = 0; i < 10; i++) {
students.add(r.nextBoolean() ?
new Graduate(i+1, r.nextDouble() * 4) :
new Undergraduate(i+1, r.nextDouble() * 4));
}
Note, If you change the displayStudent() method to toString() like so
#Override
public String toString() {
return getLevel() + " ID>> " + getID() + ", GPA>> "
+ getGPA() + ", Status>> " + getStatus();
}
You can just print the object directly without having to call any method.
You will probably need to format the GPA to eliminate unnecessary precision. Check out String.format.

Problem java Set data replaced/wiped on add

I have actually a problem on a Set in my project (code below)
public static Set<BeanObject> mapToSetBean(Collection<Object> listModel) {
Set<BeanObject> listToReturn = new HashSet<>();
for (Iterator<Object> iterator = listModel.iterator(); iterator.hasNext();) {
Object model = iterator.next();
BeanObject bean = new BeanObject();
bean = mapToBean(model);
listToReturn.add(bean);
}
return listToReturn;
}
When some beans are added to the list they replace another one.
For example:
List{}
add object1 / List{object1}
add object2 / List{object1, object2}
add object1 / List{object1, object2, object3}
add object4 / List{object4, object2, object3}
The equals and the hashcode of the object are override the hashcode are all different and in debug mode we don't enter in the override equals.
When I use an ArrayList everything works but I prefer not to change the type it has a huge impact on my project.
---------------- EDIT ---------------
public static BeanObject mapToBean(Object model) {
BeanObject bean = new BeanObject();
if (model != null) {
bean.setId(model.getId());
if(model.getId() != null){
bean.setIdString(model.getId().toString());
}
if (model.getName() != null) {
bean.setName(model.getName().toLowerCase());
}
bean.setActif(model.getActif());
if (model.getShortName() != null) {
bean.setShortName(model.getShortName().toUpperCase());
}
}
return bean;
}
BeanObject
public class BeanObject implements Comparable<BeanObject> {
/**
* serial
*/
private static final long serialVersionUID = 1L;
private BigInteger id;
private String name;
private String shortName;
private Short actif;
private String idString;
public BeanObject() {
}
public BeanObject(BigInteger id, String libelle) {
this.id = id;
this.name = libelle;
}
/*
* (non-Javadoc)
*
* #see java.lang.Object#equals(java.lang.Object)
*/
#Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (!(o instanceof BeanObject)) {
return false;
}
BeanObject other = (BeanObject) o;
boolean result;
if (null == this.id) {
if (null == other.id) {
result = true;
} else {
result = false;
}
} else {
result = this.id.equals(other.id);
}
return result;
}
/*
* (non-Javadoc)
*
* #see java.lang.Object#hashCode()
*/
#Override
public int hashCode() {
return this.id.intValue() * name.hashCode() * shortName.hashCode();
}
public BigInteger getId() {
return id;
}
public void setId(BigInteger id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getShortName() {
return shortName;
}
public void setShortName(String shortName) {
this.shortName = shortName;
}
public Short getActif() {
return actif;
}
public void setActif(Short actif) {
this.actif = actif;
}
public String getIdString() {
return idString;
}
public void setIdString(String idString) {
this.idString = idString;
}
}
Are you certain the BeanObject's hashcode values are unique? That hashcode method seems like it would map a lot of objects to 0 if any of its fields hashed to 0 since it is straight multiplication. I would suggest updating to a more standardized approach for it like the following:
#Override
public int hashCode() {
return Objects.hash(id, name, shortName);
}
Objects.hash is from the java.util package.
If this still doesn't solve the problem, I would double check the hashcode results for each bean object at add time.

Using comparator interface to sort localdate

I am trying to sort a list of employees based on their date of joining.
Below is my employee class.
import java.time.LocalDate;
public class Employee {
private String name;
private String empID;
private Designation designation;
private LocalDate dateOfJoining;
private int monthlySalary;
public Employee(String name, String empID, Designation designation, LocalDate dateOfJoining, int monthlySalary) {
super();
this.name = name;
this.empID = empID;
this.designation = designation;
this.dateOfJoining = dateOfJoining;
this.monthlySalary = monthlySalary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmpID() {
return empID;
}
public void setEmpID(String empID) {
this.empID = empID;
}
public Designation getDesignation() {
return designation;
}
public void setDesignation(Designation designation) {
this.designation = designation;
}
public LocalDate getDOJ() {
return dateOfJoining;
}
public void setDOJ(LocalDate dOJ) {
dateOfJoining = dOJ;
}
public int getMonthlySalary() {
return monthlySalary;
}
public void setMonthlySalary(int monthlySalary) {
this.monthlySalary = monthlySalary;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((dateOfJoining == null) ? 0 : dateOfJoining.hashCode());
result = prime * result + ((designation == null) ? 0 : designation.hashCode());
result = prime * result + ((empID == null) ? 0 : empID.hashCode());
result = prime * result + monthlySalary;
result = prime * result + ((name == null) ? 0 : name.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 (dateOfJoining == null) {
if (other.dateOfJoining != null)
return false;
} else if (!dateOfJoining.equals(other.dateOfJoining))
return false;
if (designation == null) {
if (other.designation != null)
return false;
} else if (!designation.equals(other.designation))
return false;
if (empID == null) {
if (other.empID != null)
return false;
} else if (!empID.equals(other.empID))
return false;
if (monthlySalary != other.monthlySalary)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
#Override
public String toString() {
return "Employee [name=" + name + ", empID=" + empID + ", designation=" + designation + ", DOJ=" + dateOfJoining
+ ", monthlySalary=" + monthlySalary + "]";
}
}
And below is my Comparator class:
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Employecomparable {
public static void main(String[] args) {
List<Employee> listofemployee = new ArrayList<>();
LocalDate date1 = LocalDate.parse("2018-09-06");
LocalDate date2= LocalDate.of(2011, 12, 12);
listofemployee.add(new Employee("abc", "12345", Designation.ASE,LocalDate.of(2014, 2, 15) , 20000));
listofemployee.add(new Employee("abcd", "24680", Designation.SE, date1, 30000));
listofemployee.add(new Employee("abcde", "13570", Designation.SSE, LocalDate.of(2013, 05, 30), 40000));
listofemployee.add(new Employee("abcdef", "13690", Designation.TL, date2, 60000));
listofemployee.add(new Employee("xyz", "10909", Designation.AM, LocalDate.parse("20/03/2000"), 800000));
listofemployee.add(new Employee("koool", "89076", Designation.M, LocalDate.parse("31/01/2011"), 2000));
Collections.sort(listofemployee, new Comparator<Employee>() {
#Override
public int compare(Employee emp1, Employee emp2) {
if (emp1.getMonthlySalary() > emp2.getMonthlySalary())
return -1;
else if (emp1.getMonthlySalary() < emp2.getMonthlySalary())
return +1;
else
return 0;
}
});
System.out.println(listofemployee);
Collections.sort(listofemployee, new Comparator<Employee>(){
#Override
public int compare(Employee emp1, Employee emp2) {
if(emp1.getDOJ()>emp2.getDOJ())
return +1;
return 0;
}
});
But while trying to sort the list of employees based on their DOJ, I am getting error "The operator > is undefined for the argument type(s) java.time.LocalDate, java.time.LocalDate".
Can someone please help me on this?
dateOfJoining is a LocalDate which you cannot compare by >, < or ==. Java only supports those mathematical symbols on primitives (and their object representations). Instead you can use the methods .isBefore() or .isAfter(), see here.
Example:
Collections.sort(listofemployee, new Comparator<Employee>(){
#Override
public int compare(Employee emp1, Employee emp2) {
if(emp1.getDOJ().isBefore(emp2.getDOJ()))
return +1;
else if (emp1.getDOJ().isAfter(emp2.getDOJ)))
return -1
else
return 0;
}
});
Alternatively:
Collections.sort(listofemployee, new Comparator<Employee>(){
#Override
public int compare(Employee emp1, Employee emp2) {
return emp1.getDOJ().compareTo(emp2.getDOJ);
}
});

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?
#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.

BeanListHandler from dbutils library cannot create java class objects from a database resultset

I have created a class called Product and a table having the same name (Product) in apache derby database. Now i want to get the corresponding Product objects whenever i retrieve the rows from the database using BeanListHandler but always get an error. I have searched almost everywhere for solutions after which i still don't see where i went wrong in my code. Can someone please tell me where i am wrong. my code is shown below.
public class Product {
private long uniqueId; //Auto increment
private String productCode;
private String productName;
private String productCategory;
private boolean available;
private double productPrice;
private int quantityOnHand;
public Product(long uniqueId, String productCode, String productName, String productCategory, boolean available, double productPrice, int quantityOnHand) {
this.uniqueId = uniqueId; //Auto increment
this.productCode = productCode;
this.productName = productName;
this.productCategory = productCategory;
this.available = available;
this.productPrice = productPrice;
this.quantityOnHand = quantityOnHand; }
#Override
public String toString() {
return "Product{" + "uniqueId=" + uniqueId + ", productCode=" + productCode + ", productName=" + productName + ", productCategory=" + productCategory + ", available=" + available + ", productPrice=" + productPrice + ", quantityOnHand=" + quantityOnHand + '}';
}
public long getUniqueId() {
return uniqueId;
}
public String getProductCode() {
return productCode;
}
public String getProductName() {
return productName;
}
public String getProductCategory() {
return productCategory;
}
public boolean isAvailable() {
return available;
}
public double getProductPrice() {
return productPrice;
}
public int getQuantityOnHand() {
return quantityOnHand;
}
public void setUniqueId(long uniqueId) {
this.uniqueId = uniqueId;
}
public void setProductCode(String productCode) {
this.productCode = productCode;
}
public void setProductName(String productName) {
this.productName = productName;
}
public void setProductCategory(String productCategory) {
this.productCategory = productCategory;
}
public void setAvailable(boolean available) {
this.available = available;
}
public void setProductPrice(double productPrice) {
this.productPrice = productPrice;
}
public void setQuantityOnHand(int quantityOnHand) {
this.quantityOnHand = quantityOnHand;
}
#Override
public int hashCode() {
int hash = 5;
hash = 53 * hash + (int) (this.uniqueId ^ (this.uniqueId >>> 32));
hash = 53 * hash + Objects.hashCode(this.productCode);
hash = 53 * hash + Objects.hashCode(this.productName);
hash = 53 * hash + Objects.hashCode(this.productCategory);
hash = 53 * hash + (this.available ? 1 : 0);
hash = 53 * hash + (int) (Double.doubleToLongBits(this.productPrice) ^ (Double.doubleToLongBits(this.productPrice) >>> 32));
hash = 53 * hash + this.quantityOnHand;
return hash;
}
#Override
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Product other = (Product) obj;
if (!Objects.equals(this.productCode, other.productCode)) {
return false;
}
if (!Objects.equals(this.productName, other.productName)) {
return false;
}
if (!Objects.equals(this.productCategory, other.productCategory)) {
return false;
}
return true;
}
}
Below is the method to retrieve the Product rows and convert then into Product Objects. I have already imported and created every component needed to establish connection and perform the query(like private QueryRunner queryRunner=new QueryRunner();
private static final List EMPTY_PRODUCT_LIST=new ArrayList<>(); etc)
public List<Product> searchAllProducts() {
ResultSetHandler<List<Product>> p = new BeanListHandler<>(Product.class);
try{
return (List<Product>) queryRunner.query(connection, "SELECT * FROM PRODUCT", p);
}
catch(SQLException e){
e.printStackTrace();
}
finally{
try {
DbUtils.close(connection);
} catch (SQLException ex) {
Logger.getLogger(ProductDatabaseHandler.class.getName()).log(Level.SEVERE, null, ex);
}
}
return EMPTY_PRODUCT_LIST; }
And below is the error that i get.
Fri Dec 02 20:05:35 EAT 2016 : Apache Derby Network Server - 10.11.1.2 - (1629631) started and ready to accept connections on port 1555
java.sql.SQLException: Cannot create main.java.models.Product:
main.java.models.Product Query: SELECT * FROM PRODUCT Parameters: []
at org.apache.commons.dbutils.AbstractQueryRunner.rethrow(AbstractQueryRunner.java:392)
at org.apache.commons.dbutils.QueryRunner.query(QueryRunner.java:351)
at org.apache.commons.dbutils.QueryRunner.query(QueryRunner.java:226)
at main.java.database.ProductDatabaseHandler.searchAllProducts(ProductDatabaseHandler.java:226)
I think you need to have a no-arg constructor for your Product class with appropriate setter methods.
BeanProcessor is responsible for converting Resultset into bean and below is the code where it creates the new instance of bean.
protected <T> T newInstance(Class<T> c) throws SQLException {
try {
return c.newInstance();
} catch (InstantiationException e) {
throw new SQLException(
"Cannot create " + c.getName() + ": " + e.getMessage());
}
Clearly it expects a no-arg constructor

Categories

Resources