Best way to handle mutable fields while making a class Immutable - java

I want to make Footballer class immutable, it has Address field which is mutable, so what is the best way to make it immutable,
Typically for HomeAddress and Area,I can use
Clone
Serialization
Copy Constructor
Since clone is broken,How to chose between copy constructor or Serialization.
package com.javaeight;
import java.util.ArrayList;
import java.util.List;
public class ImmutableDemo {
public static void main(String[] args) {
String name = "ronaldo";
int age = 27;
List<String> clubs = new ArrayList<>();
clubs.add("MU");
clubs.add("BC");
Area area = new Area(22, 11);
HomeAddress address = new HomeAddress("Bangalore", "India", area);
Footballer footballer = new Footballer(name, age, clubs, address);
}
}
final class Footballer {
private final String name;
private final int age;
private final List<String> clubs;
private final HomeAddress address;
public Footballer(String name, int age, List<String> clubs, HomeAddress homeAddress) {
this.name = name;
this.age = age;
this.clubs = new ArrayList<>(clubs);
this.address = new HomeAddress(homeAddress.getCity(), homeAddress.getCountry(), homeAddress.getArea());
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public List<String> getClubs() {
return new ArrayList<>(clubs);
}
#Override
public String toString() {
return "Footballer{" +
"name='" + name + '\'' +
", age=" + age +
", clubs=" + clubs +
'}';
}
}
class HomeAddress {
private String city;
private String country;
private Area area;
public HomeAddress(String city, String country, Area area) {
this.city = city;
this.country = country;
this.area = area;
}
public String getCity() {
return city;
}
public String getCountry() {
return country;
}
public Area getArea() {
return area;
}
}
class Area {
private int Street;
private int buildingNumber;
public Area(int street, int buildingNumber) {
Street = street;
this.buildingNumber = buildingNumber;
}
public int getStreet() {
return Street;
}
public int getBuildingNumber() {
return buildingNumber;
}
}

Related

How can I retreive a custom object from Firestore which references another custom object?

I have a User class and a Pet class. A user can have multiple pets.
I'm trying to retreive a user document and convert it to a user object as follows:
loggedInUser = documentSnapshot.toObject(User.class);
It throws the following exception:
java.lang.RuntimeException: Could not deserialize object. Can't convert object of type com.google.firebase.firestore.DocumentReference to type com.example.pawsibilities.Pet (found in field 'pets.[0]')
Here is an example of a user in firestore. One of its fields is an array of references (pets).
My pet class look like this in Firestore, and it looks like this in Java:
public class Pet {
private String name;
private String type;
private LocalDate birthday;
private String breed;
public enum Gender {
Female,
Male,
Unknown
}
private Gender gender;
private boolean neutered;
private float height;
private float weight;
private String healthNotes;
private boolean lostStatus = false;
private LocalDate lostSince = null;
private ArrayList<LastSeenDetails> lastSeenDetailsList = null;
public Pet() { }
public Pet(String name, String type, LocalDate birthday, String breed, Gender gender, Boolean neutered, float height, float weight, String healthNotes) {
this.name = name;
this.type = type;
this.birthday = birthday;
this.breed = breed;
this.gender = gender;
this.neutered = neutered;
this.height = height;
this.weight = weight;
this.healthNotes = healthNotes;
}
public String getName() {
return name;
}
public String getType() {
return type;
}
public String getBirthday() {
return birthday.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG));
}
public String getLostSince() {
return lostSince.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT));
}
public String getBreed() {
return breed;
}
public String getGender() {
return gender.name();
}
public String getHeight() {
return height + " cm";
}
public String getWeight() {
return weight + " kg";
}
public String getHealthNotes() {
return healthNotes;
}
public ArrayList<LastSeenDetails> getLastSeenDetailsList() {
return lastSeenDetailsList;
}
public boolean isLost(){ return lostStatus; }
public String isNeutered() {
if (neutered == true) {
return "Yes";
} else
return "No";
}
public void setLostStatus(boolean lostStatus) {
this.lostStatus = lostStatus;
}
public void setLostSince(LocalDate time) { this.lostSince = time; }
public void setLastSeenDetailsList(ArrayList<LastSeenDetails> lastSeenDetailsList) {
this.lastSeenDetailsList = lastSeenDetailsList;
}
}
It has an empty constructor and all fields have a getter method. I can't seem to find the issue...
It's not necessary to convert document to User, as the retrieved document is an object of type User.
Try this,
User user = documentSnapshot.getData();
or
User user = documentSnapshot.get(String field);

Problems with One to many relationship Java JPA

I have a problem with my JPA.
Basically my Couriers are created by the program and the customer and parcels are created by user while running. When I try to add a new parcel I add the object to parcel list in Customer and parcel list in Courier. But it crashes when tries to add to Courier parcel list. I create a courier object before calling my menu in the main class
And it throws the following error:
During synchronization a new object was found through a relationship that was not marked cascade PERSIST: Courier:
Id: 0
Name: null
Vehicle: null.
This is my code:
#Entity
#SequenceGenerator(name="cou_seq", initialValue=1, allocationSize=1)
#SuppressWarnings("SerializableClass")
public class Courier implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator="cou_seq")
private int couId;
private String name;
private String vehicle;
#OneToMany(mappedBy = "courier", cascade = CascadeType.PERSIST)
private List<Parcel> plist = new ArrayList<>();
public Courier(){
}
public Courier(String nameIn, String vehicleIn){
name = nameIn;
vehicle = vehicleIn;
}
public void addParcel(Parcel p1){
plist.add(p1);
p1.setCo(this);
}
public int getCouId() {
return couId;
}
public String getName() {
return name;
}
public String getVehicle() {
return vehicle;
}
public void setCouId(int couId) {
this.couId = couId;
}
public void setName(String name) {
this.name = name;
}
public void setVehicle(String vehicle) {
this.vehicle = vehicle;
}
public List<Parcel> getParcel(){
return plist;
}
public void setParcel(List<Parcel> parcels) {
plist = parcels;
}
#Override
public String toString(){
return "Courier: \nId: " + couId + "\nName: " + name + "\nVehicle: " + vehicle;
}
//CUSTOMER CLASS
#Entity
#SequenceGenerator(name="cus_seq", initialValue=1, allocationSize=1)
#SuppressWarnings("SeralizableClass")
public class Customer implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator="cus_seq")
private int cusId;
private String login;
private String password;
private String fname;
private String lname;
private String dob;
private String address;
private String phoneNo;
private String email;
#OneToMany(mappedBy = "customer")
private List<Parcel> plist = new ArrayList<>();
public Customer(){
}
public Customer(String loginIn, String passwordIn, String fnameIn, String lnameIn, String dobIn, String addressIn, String phoneNoIn, String emailIn){
login = loginIn;
password = passwordIn;
fname = fnameIn;
lname = lnameIn;
dob = dobIn;
address = addressIn;
phoneNo = phoneNoIn;
email = emailIn;
}
public void addParcel(Parcel p) {
plist.add(p);
p.setC(this);
}
public String getFname() {
return fname;
}
public String getLname() {
return lname;
}
public String getDob() {
return dob;
}
public String getAddress() {
return address;
}
public String getPhoneNo() {
return phoneNo;
}
public String getEmail() {
return email;
}
public void setFname(String fname) {
this.fname = fname;
}
public void setLname(String lname) {
this.lname = lname;
}
public void setDob(String dob) {
this.dob = dob;
}
public void setAddress(String address) {
this.address = address;
}
public void setPhoneNo(String phoneNo) {
this.phoneNo = phoneNo;
}
public void setEmail(String email) {
this.email = email;
}
public List<Parcel> getParcel(){
return plist;
}
public void setParcel(List<Parcel> parcels) {
plist = parcels;
}
public String toString(){
return "Customer: " + "\nID: " + cusId + "\nLogin: " + login + "\nFirst Name: " + fname + "\nSecond Name: " + lname + "\nDOB: " + dob + "\nAddress: " + address + "\nPhone No: " + phoneNo;
}
}
//PARCEL CLASS
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "type")
#SequenceGenerator(name = "par_seq", initialValue = 1, allocationSize = 1)
#SuppressWarnings("SerializableClass")
public class Parcel {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "par_seq")
private int parId;
private double height;
private double width;
private double length;
private double weight;
private String receiver;
#ManyToOne()
#JoinColumn(name = "cuId")
private Customer customer;
#ManyToOne()
#JoinColumn(name = "coId")
private Courier courier;
private static double price;
public Parcel() {
}
public Parcel(double heightIn, double widthIn, double lengthIn, double weightIn, String receiverIn) {
height = heightIn;
width = widthIn;
length = lengthIn;
weight = weightIn;
receiver = receiverIn;
}
public double getHeight() {
return height;
}
public double getWidth() {
return width;
}
public double getLength() {
return length;
}
public double getWeight() {
return weight;
}
public double getPrice() {
return price;
}
public void setHeight(double height) {
this.height = height;
}
public void setWidth(double width) {
this.width = width;
}
public void setLength(double length) {
this.length = length;
}
public void setWeight(double weight) {
this.weight = weight;
}
public void setPrice(double price) {
this.price = price;
}
public double calcSize(double height, double width, double length) {
return height * width * length;
}
public void setC(Customer c) {
this.customer = c;
}
public Customer getC() {
return customer;
}
public void setCo(Courier c1) {
this.courier = c1;
}
public Courier getCo() {
return courier;
}
#Override
public String toString() {
return "Parcel:\nHeight: " + height + "\nWidth: " + width + "\nLength: " + length + "\nWeight: " + weight;
}
}
//JPA method that adds a new parcel
public Parcel createParcel(double heightAdd, double widthAdd, double lengthAdd, double weightAdd, String receiverAdd,String owner,String type){
int id = findCustomerIdByLogin(owner);
Customer c = em.find(Customer.class, id);
Courier co = new Courier();
em.getTransaction().begin();
if(type.equals("INT")){
System.out.println("Inside here");
InternationalParcel int1 = new InternationalParcel(heightAdd, widthAdd, lengthAdd, weightAdd, receiverAdd);
em.persist(int1);
c.addParcel(int1);
//em.persist(int1);
co.addParcel(int1);
em.getTransaction().commit();
return int1;
} else {
NationalParcel nat1 = new NationalParcel(heightAdd, widthAdd, lengthAdd, weightAdd,receiverAdd);
em.persist(nat1);
c.addParcel(nat1);
em.persist(nat1);
co.addParcel(nat1);
em.getTransaction().commit();
return nat1;
}
}
You are adding your Parcel to a Courier that is not persisted in the Database yet.
You have to Persist your Courier Object as well.
Since you told your Courier Object that it should cascade persist its Parcel objects it should actually be enough to just persist the Courer without persisting each parcel on its own:
Parcel parcel;
Customer c = em.find(Customer.class, id);
Courier co = new Courier();
em.getTransaction().begin();
if(type.equals("INT")){
parcel = new InternationalParcel(heightAdd, widthAdd, lengthAdd, weightAdd, receiverAdd);
} else {
parcel = new NationalParcel(heightAdd, widthAdd, lengthAdd, weightAdd,receiverAdd);
}
co.addParcel(parcel);
em.persist(co); // <- This is what you are currently not doing!
em.persist(parcel); // <- this might not be necessary because of cascade persist
c.addParcel(parcel);
em.getTransaction().commit();
return parcel;

Work with methods, setters and getters in java

I have this class:
public class Person
{
/**
*
*/
private static final long serialVersionUID = 1L;
private String firstName = "Vasya";
private String lastName = "Pupkin";
private Integer age = 58;
private Integer phone = 2;
#Override
public String toString()
{
return "Person [firstName=" + firstName + ", lastName=" + lastName
+ ", age=" + age + "]";
}
public void setName(String name)
{
firstName = name;
}
public void setLastName(String lName)
{
lastName = lName;
}
public void setAge(Integer personAge)
{
age = personAge;
}
public void setPhone(Integer personPhone)
{
phone = personPhone;
}
public String getName()
{
return firstName;
}
public String getLastName()
{
return lastName;
}
public Integer getAge()
{
return age;
}
public Integer getPhone()
{
return phone;
}
public void Init()
{
this.setName("");
this.setLastName("");
this.setPhone(0);
this.setAge(0);
}
}
I create an variable: Person somePerson, then I call method setName from that variable somePerson:
somePerson.setName("");
but it raises an error.
Based on the provided code, the following should work:
Person somePerson = new Person();
somePerson.setName("");
If it doesn't, then something else is going on.

I'm trying to write a personclass and a personTester in Java

So far for my personClass, I have the following:
package personclass;
public class Personclass {
private static boolean Personclass;
private int PersonCount;
public int getPersonCount()
{
return PersonCount;
}
private String FirstName;
private String LastName;
private int Age;
private Double Height;
private String Gender;
public Personclass(String foreName, String surName, int age, Double height, String gender)
{
FirstName = foreName;
LastName = surName;
Age = age;
Height = height;
Gender = gender;
}
private String getFirstName()
{
return FirstName;
}
private void setFirstName(String foreName)
{
this.FirstName = foreName;
}
private String getLastName()
{
return LastName;
}
private void setLastName(String surName)
{
this.LastName = surName;
}
private int getAge()
{
return Age;
}
private void setAge(int age)
{
this.Age = age;
}
private Double getHeight()
{
return Height;
}
private void setHeight(Double height)
{
this.Height = height;
}
private String getGender()
{
return Gender;
}
private void setGender(String gender)
{
this.Gender = gender;
}
/**
*
* #param FirstName
* #param LastName
* #param Age
* #param Height
* #param Gender
*/
public Personclass(String FirstName, String LastName, int Age, double Height, String Gender)
{
this.FirstName = FirstName;
this.LastName = LastName;
this.Age = Age;
this.Height = Height;
this.Gender = Gender;
++PersonCount;
}
/**
*
* #return
*/
#Override
public String toString()
{
return "Person[forename=" + getFirstName() + ", surname=" + getLastName() + ", age=" + getAge() + ", height=" + getHeight() +"m" + ", gender=" + getGender() +"]";
}
public String format()
{
return String.format("%10s %10s %10d %10.2f %10s", getFirstName() , getLastName() , getAge() , getHeight() , getGender());
}
public static void main(String[] args)
{
}
}
And for my personTester, I have the following code:
package personclass;
public class PersonTester
{
public static void main(String[] args)
{
Person person1 = new Person("Joe","Smith",25,1.57,"Male");
Person person2 = new Person("Sain","Davies",18,1.73,"Female");
Person person3 = new Person("John","White",22,1.60,"Male");
Person person4 = new Person("Martin","Taylor",26, 1.54,"Male");
Person person5 = new Person("Jessica","Clarke",19,1.70,"Female");
System.out.println(person1.toString());
System.out.println(person2.toString());
System.out.println(person3.toString());
System.out.println(person4.toString());
System.out.println(person5.toString());
}
}
The thing that I'm having trouble with is not being about to print anything out when I try and run the personTester. How would I go about trying to print the five different people out?
You need to make the objects in main() in class PersonTester type Personclass. That should enable you to print the information about the people, through the toString() method in that class.
There can be two possible solutions.
You should make sure that you are running the PersonTester class, but not Personclass. i.e., You should be using java PersonTester command if you are running from command line.
The name of your class is Personclass but in your PersonTester class, you are referring to some Person class. You should change the Personclass to something like the following.
package personclass;
public class PersonTester{
public static void main(String[] args) {
Personclass person1 = new Personclass ("Joe","Smith",25,1.57,"Male");
Personclass person2 = new Personclass ("Sain","Davies",18,1.73,"Female");
Personclass person3 = new Personclass ("John","White",22,1.60,"Male");
Personclass person4 = new Personclass ("Martin","Taylor",26, 1.54,"Male");
Personclass person5 = new Personclass ("Jessica","Clarke",19,1.70,"Female");
System.out.println(person1.toString());
System.out.println(person2.toString());
System.out.println(person3.toString());
System.out.println(person4.toString());
System.out.println(person5.toString());
}
}

Return result from a constructor from another class in java

Here is the first file and there is another to follow, to really explain my question; my question starts in the public Account getbankAddress() method.
public class Bank {
String bankName;
int bankID;
Address address = new Address();
public Bank(){
bankName = "?";
bankID = 0;
}
public String getBankName(){
return bankName;
}
public int getBankID(){
return bankID;
}
public Address getBankAddress(){
// This is where I'm having trouble getting the bank address from the address class,
// How can I produce a result from the mutator method of setCity and setState methods?
return address;
}
public void setBankName(String bankName1){
bankName = bankName1;
}
public void setBankID(int ID){
bankID = ID;
}
public void setBankAddress(String aCity, String aState){
aCity = "city";
aState = "state";
}
public String toString(){
String str = ("\nBank name:\t\t" + bankName + "\nBank ID:\t\t" + bankID +
"\nBank address:\t\t" + bankAddress + "\n\n");
return str;
}
}
public class Address{
private String city;
private String state;
public Address(){
city = "?";
state = "?";
}
public String getCity(){
return city;
}
public String getState(){
return state;
}
public void setCity(String aCity){
aCity = city;
}
public void setState(String aState){
aState = state;
}
public String toString(){
String str1 = (city + "," + state);
return str1;
}
}
I think changing this:
public void setBankAddress(String aCity, String aState){
aCity = "city";
aState = "state";
}
to
public void setBankAddress(String aCity, String aState) {
address.setCity(aCity);
address.setState(aState);
}
should work.
++++++++++++++++
Also, change this:
public void setCity(String aCity){
aCity = city;
}
public void setState(String aState){
aState = state;
}
to
public void setCity(String aCity){
city = aCity;
}
public void setState(String aState){
state = aState;
}

Categories