Changing object values only when save() method is called - java

I need help passing a test, but can't seem to find the solution anywhere. I have a code for determining the bonus points for customers. I get my info from a text file and I need to give customers bonus points based on vairables. The catch is that the bonus points should only be added when used the save() method, which overwrites the text file. I have a CustomerRepository class:
public class CustomerRepository {
private static final String FILE_PATH = "src/poly/customer/data.txt";
public List<AbstractCustomer> customers;
public CustomerRepository() {
try {
this.customers = readFiles();
} catch (IOException e) {
e.printStackTrace();
}
}
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
public List<AbstractCustomer> readFiles() throws IOException{
List<AbstractCustomer> result = new ArrayList<>();
List<String> lines = Files.readAllLines(Path.of(FILE_PATH));
for (String line : lines) {
String[] parts = line.split(";");
int points = Integer.parseInt(parts[3]);
if (parts[0].equals("REGULAR")) {
LocalDate date = LocalDate.parse(parts[4], formatter);
RegularCustomer customer = new RegularCustomer(parts[1], parts[2], points, date);
result.add(customer);
} else if (parts[0].equals("GOLD")) {
GoldCustomer customer = new GoldCustomer(parts[1], parts[2], points);
result.add(customer);
} else {
throw new IOException();
}
}
return result;
}
public void save(AbstractCustomer customer) {
if (!(customers.contains(customer))) {
customers.add(customer);
}
StringBuilder result = new StringBuilder();
for (AbstractCustomer client : customers) {
result.append(client.toString());
result.append("\n");
}
try{
File file = new File(FILE_PATH);
FileWriter fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
bw.write(result.toString());
bw.close();
}catch(IOException e){
e.printStackTrace();
}
}
This class is working, but I don't know how to give customer objects points only when they are saved. I also have RegularCustomer and GoldCustomer classes which extend the AbstractCustomer class:
public abstract sealed class AbstractCustomer permits GoldCustomer, RegularCustomer {
protected String id;
protected String name;
protected int bonusPoints;
public AbstractCustomer(String id, String name, int bonusPoints) {
this.id = id;
this.name = name;
this.bonusPoints = bonusPoints;
}
public abstract void collectBonusPointsFrom(Order order);
public String getId() {
return id;
}
public String getName() {
return name;
}
public Integer getBonusPoints() {
return bonusPoints;
}
The code itself is working fine and does the intended things, but my only problem is passing this test:
#Test
public void customerIsChangedOnlyWhenSaved() {
String randomId = UUID.randomUUID().toString();
repository.save(new RegularCustomer(
randomId, "David", 0, LocalDate.now()));
AbstractCustomer customer = repository.getCustomerById(randomId).get();
assertThat(customer.getBonusPoints(), is(0));
customer.collectBonusPointsFrom(new Order(200, LocalDate.now()));
assertThat(customer.getBonusPoints(), is(not(0)));
AbstractCustomer loaded = repository.getCustomerById(randomId).get();
assertThat(loaded.getBonusPoints(), is(0));
}
This test creates a new customer and adds a order, but the customer bonuspoints should not change, because it is not saved. My code still adds the points and overwrites the file.
There is also a BonusCollector class, which collects bonus points from order, but this class shouldn't be modified.
This is the implementation for collectBonusPoints(Order order):
#Override
public void collectBonusPointsFrom(Order order) {
if (order.getTotal() >= 100) {
double points = order.getTotal();
if (isWithinAMonth(order.getDate())) {
this.bonusPoints += Math.toIntExact(Math.round(points * 1.5));
this.lastOrderDate = order.getDate();
} else {
this.bonusPoints += Math.toIntExact(Math.round(points));
this.lastOrderDate = order.getDate();
}
}
}
The gold customer implementation is a bit different.

The problem is with persisting state.In abstractcustomer class you need to have get method and from this method to return the clone of the object to be able to pass the test.
public class Customer {
protected String id;
protected String name;
protected int bonusPoints;
public Customer(String id, String name, int bonusPoints) {
this.id = id;
this.name = name;
this.bonusPoints = bonusPoints;
}
public void collectBonusPointsFrom(Order order) {
....
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public Integer getBonusPoints() {
return bonusPoints;
}
public Customer get(){
//if you don`t return new object you will work directly with the one from repo
return new Customer(id,name,bonusPoints);
}
}
The full code you can find -> https://drive.google.com/file/d/1FOeF68RO-qI4CO9mJ92rKlQ8MNigWbof/view?usp=sharing

Related

Send array data from one class to another JAVA

(I'm a beginner so this may sound obvious/lack information.) I have an ArrayList of attributes for different pets including attributes such as their given-name, common-name, the price of the animal, sex, date bought and date sold. this information is generated from a separate class that adds an array of information to an array of arrays of the already existing list of animals. Essentially, I want to send the array to another class (called Pets) so it can then be added to the array of arrays. I understand this may sound confusing but this is the only way I can word it, I can clarify anything if needed. Any help would be great as I'm really stuck and can't work out how to send it. This is the code that generates my values in the array (using text-boxes to input the information).
public void actionPerformed(ActionEvent e) {
ArrayList<String> NewanimalArr = new ArrayList<>();
String givenName = txtGivenname.getText();
String commonName = txtCommonName.getText();
String priceOf = txtPrice_1.getText();
String sexOf = txtSex.getText();
String colourOf = txtMaincolour.getText();
String dateOfA = txtArrivaldate.getText();
String dateSold = txtSellingdate.getText();
NewanimalArr.add(givenName);
NewanimalArr.add(commonName);
NewanimalArr.add(priceOf);
NewanimalArr.add(sexOf);
NewanimalArr.add(colourOf);
NewanimalArr.add(dateOfA);
NewanimalArr.add(dateSold);
System.out.println(NewanimalArr);
}
});
this will then print information generated that is entered for example:
[alex, Dog, 40.50, Male, Brown, 14/04/2015, 14/12/2016]
how do I then send this data to another class
Option one Constructor Injection:
public class Foo {
List<String> actionPerformed(ActionEvent e) {
List<String> newanimalArr = new ArrayList<>();
.....
return newanimalArr
}
...
public class Pets {
private final List<String> array;
public Pets(final List<String> array) {
this.array = array;
}
void bar() {
System.out.println(this.array);
}
}
....
public static void main(String[] args) {
Foo foo = new Foo();
Pets pets = new Pets(foo.actionPerformed( new ActionEvent() ) );
pets.bar();
}
Option two Getter-Setter Injection:
public class Foo {
private final List<String> newanimalArr;
public Foo() {
this.newanimalArr = new ArrayList<>();
}
public void actionPerformed(ActionEvent e) {
.....
}
public List<String> getNewanimalArr() {
return new ArrayList<String>(newanimalArr);
}
}
...
public class Pets {
private List<String> array;
public Pets() {
this.array = Collections.<String>emptyList();
}
public void setArray(final List<String> array) {
this.array = array;
}
public void bar() {
System.out.println(this.array);
}
}
....
public static void main(String[] args) {
Foo foo = new Foo();
foo.actionPerformed( new ActionEvent() );
Pets pets = new Pets();
bar.setArray( foo.getNewanimalArr() );
pets.bar();
}
See also Dependency Injection Patterns
Create a class definition of Pet, using instance variables for the fields. In Java it is custom to create a setXyz and a getXyz for each xyz field. You can also create a constructor in which you pass all the values and assign them to the fields, this minimizes the risk of fields not being filled in.
The initial ArrayList you are creating doesn't add that much use, it is easier to create the Pet instances directly:
List<Pet> newArrivals = new ArrayList<>();
// get data from view fields and if necessary transform them to other objects such as:
LocalDate arrivedOn = LocalDate.parse(txtArrivaldate.getText(), DateTimeFormatter.ofLocalizedDate(FormatStyle.FormatStyle);
// create and add a new Pet object to the list
newArrivals.add(new Pet(.....));
public class Pet {
public enum Gender {
FEMALE, MALE
}
private String givenName;
private String commonName;
private double price;
private Gender gender;
private String color;
private LocalDate arrivedOn;
private LocalDate soldOn;
public Pet() {
}
public Pet(String givenName, String commonName, double price, Gender gender, String color, LocalDate arrivedOn,
LocalDate soldOn) {
super();
this.givenName = givenName;
this.commonName = commonName;
this.price = price;
this.gender = gender;
this.color = color;
this.arrivedOn = arrivedOn;
this.soldOn = soldOn;
}
public String getGivenName() {
return givenName;
}
public void setGivenName(String givenName) {
this.givenName = givenName;
}
public String getCommonName() {
return commonName;
}
public void setCommonName(String commonName) {
this.commonName = commonName;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Gender getGender() {
return gender;
}
public void setGender(Gender gender) {
this.gender = gender;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public LocalDate getArrivedOn() {
return arrivedOn;
}
public void setArrivedOn(LocalDate arrivedOn) {
this.arrivedOn = arrivedOn;
}
public LocalDate getSoldOn() {
return soldOn;
}
public void setSoldOn(LocalDate soldOn) {
this.soldOn = soldOn;
}
}

spring data cassandra saving only a single object in the list

Model
#Table(value = "bad_data")
public class BadData {
private String objectID;
private String type;
private String problems;
private String owner;
private String formattedID;
private String project;
#PrimaryKey
private String train;
private String status;
/* Default constructor. */
public BadData () {
this.objectID = "";
this.type = "";
this.problems = "";
this.owner = "";
this.formattedID = "";
this.project = "";
this.train = "";
this.status = "";
}
/* Getters and setters. */
public void setObjectID (String objectID) {
this.objectID = objectID;
}
public String getObjectID () {
return this.objectID;
}
public void setType (String type) {
this.type = type;
}
public String getType () {
return this.type;
}
public void setProblems (String problems) {
this.problems = problems;
}
public String getProblems () {
return this.problems;
}
public void setOwner (String owner) {
this.owner = owner;
}
public String getOwner () {
return this.owner;
}
public void setFormattedID (String formattedID) {
this.formattedID = formattedID;
}
public String getFormattedID () {
return this.formattedID;
}
public void setProject (String project) {
this.project = project;
}
public String getProject () {
return this.project;
}
public void setTrain (String train) {
this.train = train;
}
public String getTrain () {
return this.train;
}
public void setStatus (String status) {
this.status = status;
}
public String getStatus () {
return this.status;
}
}
Repository
#Autowired
public void save (CassandraOperations db) {
BadData badData1 = new BadData();
badData1.setTrain("train");
badData1.setFormattedID("fid");
badData1.addProblems("problem1");
badData1.setObjectID("id");
badData1.setOwner("lokesh");
badData1.setType("story");
badData1.setProject("om");
badData1.setStatus("open");
BadData badData2 = new BadData();
badData2.setTrain("train");
badData2.setFormattedID("fid");
badData2.addProblems("problem2");
badData2.setObjectID("id");
badData2.setOwner("lokesh");
badData2.setType("story");
badData2.setProject("om");
badData2.setStatus("open");
BadData badData3 = new BadData();
badData3.setTrain("train");
badData3.setFormattedID("fid");
badData3.addProblems("problem3");
badData3.setObjectID("id");
badData3.setOwner("lokesh");
badData3.setType("story");
badData3.setProject("om");
badData3.setStatus("open");
List<BadData> data = new ArrayList<>();
data.add(badData1);
data.add(badData3);
data.add(badData2);
db.insert(data);
}
I am trying to save three objects placing them in list. I got only one object (badData3) saved into the database. I changed the order of those objects in the list. i noticed that which ever object is in the middle of the list is getting saved. Can some one guess what could be the possible error be
Yes (krsyk is correct), the value ("train") of your #PrimaryKey field (train) is the same for all entities in your List.
Also, you should have a look at the corresponding test case (insertBatchTest) in test class (CassandraDataOperationsTest) in the SD Cassandra test suite.
For reassurance, I added the following code snippet to the end of the test...
assertThat(template.count(Book.class), is(equalTo(80l)));
And, the test passed as expected.
Note, I was using the latest Spring Data Cassandra 1.4.2.RELEASE.
Also note, because every INSERT or UPDATE in Cassandra is actually an "UPSERT" (see here), then you are effectively overwriting each entry (entity) in your List because of the duplicate primary key value.
Your #PrimaryKey is train field, and you set this field in each object to the same value: "train" so they will override each other.

How to check if an array in an arraylist contains a certain value?

I have an array list which contains arrays of type String. I create the array list and add arrays to it with the following code:
List<String[]> transaction = new ArrayList<String[]>();
String[] transactionLine = new String[7];
transactionLine[0] = "0";
transactionLine[1] = "1";
//.....
transactionLine[6] = "some value";
transactionLines.add(transactionLine);
Now I want to test if one of the arrays contain a certain value. I tried it like this, but then it checks for an array and not an element of an array:
if(transactionLines.contains("some value")) {
//Do some stuff with it
}
I know this doesn't work, but I don't now how to do it otherwise. I couldn't find any post of this already on Stackoverflow (not with the logical search terms for this problem anyway).
Note: I have chosen this structure of arrays in an arraylist, because I have a fixed number of columns (as suggested in how to create dynamic two dimensional array in java?).
Any help is greatly appreciated!
#assylias suggestion to use the object oriented way is good, but his example does not tell if the list contains a transaction where one property has a certain value. This example does:
public class Test {
public static void main(final String[] args) {
final List<TransactionLine> transaction = new ArrayList<>();
transaction.add(new TransactionLine(1, "some value"));
transaction.add(new TransactionLine(2, "another value"));
transaction.add(new TransactionLine(3, "yet another value"));
System.out.println(containsName(transaction, "some value"));
System.out.println(containsName(transaction, "non-existent value"));
}
// Iterates over all transactions until a transaction is found that has the
// same name as specified in search
private static boolean containsName(final List<TransactionLine> transaction, final String search) {
for (final TransactionLine transactionLine : transaction) {
if (transactionLine.getName().equals(search)) {
return true;
}
}
return false;
}
private static class TransactionLine {
private int id;
private String name;
public TransactionLine(final int id, final String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(final int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
}
}
Here is an example with two classes (Transaction and TransactionLine):
Test:
public class Test {
public static void main(final String[] args) throws Exception {
final Transaction transaction = new Transaction();
transaction.add("some name");
transaction.add("another name");
transaction.add("yet another name");
System.out.println(transaction.containsName("some name"));
System.out.println(transaction.containsName("non-existent name"));
}
}
Transaction:
import java.util.ArrayList;
import java.util.List;
public class Transaction {
private final List<TransactionLine> transactionLines = new ArrayList<>();
public void add(final String name) {
final TransactionLine tl = new TransactionLine(transactionLines.size(), name);
transactionLines.add(tl);
}
public boolean containsName(final String name) {
for (final TransactionLine transactionLine : transactionLines) {
if (transactionLine.getName().equals(name)) {
return true;
}
}
return false;
}
}
TransactionLine:
public class TransactionLine {
private int id;
private String name;
public TransactionLine() {
}
public TransactionLine(final int id, final String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(final int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
}
The object oriented way of solving your problem would be to create a class:
class Transaction {
private final int id;
private final String name;
//etc.
}
Then if you need to test if a given transaction is in the list you could implement equals and hashcode in that class, which would enable you to call:
if(transactionLines.contains(someTransaction)) { ... }
If you just need to find transactions with a specific characteristics, you would need to iterate over the list and check each transaction, for example:
Transaction result = null;
for (Transaction t : transacionLines) {
if(t.getName().equals("some value") {
result = t;
break;
}
}
public static boolean isListOfStringArraysContainsString(List<String[]> arrayList, String s) {
for (String[] arr : arrayList) {
for (String string : arr) {
if ((string != null) && (string.equals(s))) {
return true;
}
}
}
return false;
}
Provided code do exactly what you are asking about, but solution provided by #assylias is proper
I got your point. By using ArrayList you are trying to make an array of another array of strings. But you have made one simple mistake.This is how you tried to retrieved a String inside an array inside an ArrayList:
if(transactionLines.contains("some value")) {
//Do some stuff with it
}
This "some value" is a string present in String array "transactionLine" and not referred by the List "transactionLines" (which is referring to ArrayList object).
Instead this is what you should have done:
List<String[]> transactionLines = new ArrayList<String[]>();
String[] transactionLine = new String[7];
transactionLine[0] = "0";
transactionLine[1] = "1";
transactionLine[2] = "something";
transactionLine[3] = "3";
transactionLine[4] = "4";
transactionLines.add(transactionLine);
String[] mySL=transactionLines.get(0);
System.out.println(mySL[2]);
if (mySL[2].equals("something")) {
//some code
} else {
//some code
}
Hope this helps.

Assign return value to new Variable (Java)

it's been a while since I've done some java coding.
I need to build an application for a business which requires automation (part of a workshop), which is however irrelevant to my question...
I'm stuck on the line : customerList.add(customer); //(part of the addCustomer method in the WCIA class)
Also it's the first time I'm told to "Assign return value to new Variable" as part of an error, so not too sure what that means.
Code: Main
import java.util.ArrayList;
public class WCIA {
private final ArrayList customerList = null;
public static void main(String[] args) {
short s =002;
Customer arno = new Customer();
arno.setName("Arno");
arno.setId(s);
arno.setEmail("arnomeye#gmail.com");
arno.setAddress("Somewhere");
arno.setPhoneNum("0727855201");
System.out.printf("%s",arno.getEmail());
WCIA wcia = new WCIA();
wcia.addCustomer(arno);
wcia.displayCustomers();
}
public void addCustomer (Customer customer)
{
customerList.add(customer); // <---Problem over here
}
public void displayCustomers()
{
for(int x=0;x<customerList.size();x++)
{
Customer cus = (Customer) customerList.get(x);
cus.DisplayCustomer();
}
}
}
Code: Customer class:
public class Customer {
private short id;
private String name;
private String email;
private String phoneNum;
private String address;
public Customer()
{
System.out.println("Class initiated");
}
public void DisplayCustomer()
{
System.out.append("Name : "+ name+"\n");
System.out.append("ID : "+ id+"\n");
System.out.append("Email : "+ email+"\n");
System.out.append("Phone Number : "+ phoneNum+"\n");
System.out.append("address : "+ address+"\n");
}
public void setId(short id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setEmail(String email) {
this.email = email;
}
public void setPhoneNum(String phoneNum) {
this.phoneNum = phoneNum;
}
public void setAddress(String address) {
this.address = address;
}
public short getId() {
return id;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
public String getPhoneNum() {
return phoneNum;
}
public String getAddress() {
return address;
}
}
You need to instantiate your ArrayList before you can assign elements to it. You're probably getting a NullPointerException, is my guess.
Change this line:
private final ArrayList customerList = null;
to
private final ArrayList customerList = new ArrayList();
Should solve at least this problem. I did not read the rest of your code so I'm not sure if other problems exist.
customerList is null and never initialized. Create an object of type ArrayList and assign it to that variable before you try to add to it.
You should declare the List with an explicit definition of the type of its elements (parametrized list):
private final List<Customer> customerList;
This way you can get rid of casting to Customer in:
Customer cus = customerList.get(x);
Finally, as good practice, initialize it in the constructor:
public WCIA()
{
customerList = new ArrayList<>();
}

Set dynamic parameter value into generic method of Java Reflection

I'm a new java developer, and I want to develop my code with reflection.
I have a class call User:
I want to pass dynamic value to those 3 methods, so in java reflection I got some code but I don't understand why?
import .....
public class user
{
private int id;
private String name;
private Date dob;
public setID(int id)
{
this.id = id;
}
public setName(String name)
{
this.name = name;
}
public setDOB(Date dob)
{
this.dob = dob;
}
}
Class cls = Class.forName("user");
Method[] methods = cls.getDeclearedMethod();
for(Method m : methods)
{
Object[] args = new Object[1];
args[0] = .....
m.invoke(cls, args[0]);
}
I don't dare to ask why you wanna do this... this way but i hope this example helps you get the feeling of some of the capabilities of reflection provided by Java.
import java.lang.reflect.Method;
import java.util.Date;
public class Ref {
public static void main(String[] args) throws ClassNotFoundException,
InstantiationException, IllegalAccessException {
Class cls = Class.forName("User");
Object o = cls.newInstance();
Object[] fieldValues = { new Integer(1), "", new Date() };
Method[] methods = cls.getDeclaredMethods();
for (Method m : methods) {
Class[] paramTypes = m.getParameterTypes();
Object[] paramValues = new Object[1];
if (paramTypes.length == 0) {
continue;
}
if (paramTypes[0].equals(Date.class)) {
paramValues[0] = new Date();
} else if (paramTypes[0].equals(String.class)) {
paramValues[0] = "nice";
} else if (paramTypes[0].equals(Integer.TYPE)) {
paramValues[0] = 2;
}
if (paramValues[0] != null) {
try {
m.invoke(o, paramValues[0]);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} // end for
} // end for
System.out.println("o = " + o);
} // end method main
} // end class Ref
class User {
private int id;
private String name;
private Date dob;
public void setID(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setDOB(Date dob) {
this.dob = dob;
}
public String toString() {
return "[id = " + id + ", name = " + name + ", date = " + dob + "]";
}
}

Categories

Resources